From 7f01c5355090a53e9f192d7ecc4f003f932a5022 Mon Sep 17 00:00:00 2001 From: Eduard Bosch Bertran Date: Wed, 24 May 2017 09:43:26 +0200 Subject: [PATCH 1/3] feat: Search $all strings starting with given strings --- src/ParseQuery.js | 30 +++++++++++++++++++++++++++++- src/__tests__/ParseQuery-test.js | 27 +++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/ParseQuery.js b/src/ParseQuery.js index 78c148853..89c9c142a 100644 --- a/src/ParseQuery.js +++ b/src/ParseQuery.js @@ -229,6 +229,13 @@ export default class ParseQuery { return this; } + /** + * Converts string for regular expression at the beginning + */ + _regexStartWith(string: string): String { + return '^' + quote(string); + } + /** * Returns a JSON representation of this query. * @method toJSON @@ -682,6 +689,27 @@ export default class ParseQuery { return this._addCondition(key, '$all', values); } + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values starting with given strings. + * @method containsAllStartingWith + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The string values that will match as starting string. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + containsAllStartingWith(key: string, values: Array): ParseQuery { + var _this = this; + if (!Array.isArray(values)) { + values = [values]; + } + + values = values.map(function (value) { + return {"$regex": _this._regexStartWith(value)}; + }); + + return this.containsAll(key, values); + } + /** * Adds a constraint for finding objects that contain the given key. * @method exists @@ -826,7 +854,7 @@ export default class ParseQuery { if (typeof value !== 'string') { throw new Error('The value being searched for must be a string.'); } - return this._addCondition(key, '$regex', '^' + quote(value)); + return this._addCondition(key, '$regex', this._regexStartWith(value)); } /** diff --git a/src/__tests__/ParseQuery-test.js b/src/__tests__/ParseQuery-test.js index c33458f1e..56cf0a3ff 100644 --- a/src/__tests__/ParseQuery-test.js +++ b/src/__tests__/ParseQuery-test.js @@ -264,6 +264,33 @@ describe('ParseQuery', () => { }); }); + it('can generate contains-all-starting-with queries', () => { + var q = new ParseQuery('Item'); + q.containsAllStartingWith('tags', ['ho', 'out']); + expect(q.toJSON()).toEqual({ + where: { + tags: { + $all: [ + {$regex: '^\\Qho\\E'}, + {$regex: '^\\Qout\\E'} + ] + } + } + }); + + q.containsAllStartingWith('tags', ['sal', 'ne']); + expect(q.toJSON()).toEqual({ + where: { + tags: { + $all: [ + {$regex: '^\\Qsal\\E'}, + {$regex: '^\\Qne\\E'} + ] + } + } + }); + }); + it('can generate exists queries', () => { var q = new ParseQuery('Item'); q.exists('name'); From 4494b86375277686f69b6086e132420a578b7c89 Mon Sep 17 00:00:00 2001 From: Eduard Bosch Bertran Date: Wed, 24 May 2017 11:26:47 +0200 Subject: [PATCH 2/3] feat: Include dist & lib folders --- .gitignore | 4 +- dist/parse.js | 13937 ++++++++++++++++ dist/parse.min.js | 18 + lib/browser/Analytics.js | 89 + lib/browser/Cloud.js | 109 + lib/browser/CoreManager.js | 161 + lib/browser/EventEmitter.js | 15 + lib/browser/FacebookUtils.js | 243 + lib/browser/InstallationController.js | 64 + lib/browser/LiveQueryClient.js | 595 + lib/browser/LiveQuerySubscription.js | 162 + lib/browser/ObjectStateMutations.js | 165 + lib/browser/Parse.js | 186 + lib/browser/ParseACL.js | 406 + lib/browser/ParseConfig.js | 228 + lib/browser/ParseError.js | 507 + lib/browser/ParseFile.js | 291 + lib/browser/ParseGeoPoint.js | 235 + lib/browser/ParseHooks.js | 162 + lib/browser/ParseInstallation.js | 65 + lib/browser/ParseLiveQuery.js | 241 + lib/browser/ParseObject.js | 2001 +++ lib/browser/ParseOp.js | 579 + lib/browser/ParsePromise.js | 740 + lib/browser/ParseQuery.js | 1340 ++ lib/browser/ParseRelation.js | 182 + lib/browser/ParseRole.js | 196 + lib/browser/ParseSession.js | 180 + lib/browser/ParseUser.js | 1150 ++ lib/browser/Push.js | 98 + lib/browser/RESTController.js | 248 + lib/browser/SingleInstanceStateController.js | 160 + lib/browser/Storage.js | 93 + lib/browser/StorageController.browser.js | 41 + lib/browser/StorageController.default.js | 41 + lib/browser/StorageController.react-native.js | 67 + lib/browser/TaskQueue.js | 77 + lib/browser/UniqueInstanceStateController.js | 189 + lib/browser/arrayContainsObject.js | 35 + lib/browser/canBeSerialized.js | 82 + lib/browser/decode.js | 93 + lib/browser/encode.js | 104 + lib/browser/equals.js | 84 + lib/browser/escape.js | 31 + lib/browser/isRevocableSession.js | 20 + lib/browser/parseDate.js | 34 + lib/browser/unique.js | 45 + lib/browser/unsavedChildren.js | 102 + lib/node/Analytics.js | 89 + lib/node/Cloud.js | 109 + lib/node/CoreManager.js | 161 + lib/node/EventEmitter.js | 15 + lib/node/FacebookUtils.js | 243 + lib/node/InstallationController.js | 64 + lib/node/LiveQueryClient.js | 595 + lib/node/LiveQuerySubscription.js | 162 + lib/node/ObjectStateMutations.js | 165 + lib/node/Parse.js | 190 + lib/node/ParseACL.js | 406 + lib/node/ParseConfig.js | 228 + lib/node/ParseError.js | 507 + lib/node/ParseFile.js | 291 + lib/node/ParseGeoPoint.js | 235 + lib/node/ParseHooks.js | 162 + lib/node/ParseInstallation.js | 65 + lib/node/ParseLiveQuery.js | 241 + lib/node/ParseObject.js | 2001 +++ lib/node/ParseOp.js | 579 + lib/node/ParsePromise.js | 740 + lib/node/ParseQuery.js | 1340 ++ lib/node/ParseRelation.js | 182 + lib/node/ParseRole.js | 196 + lib/node/ParseSession.js | 180 + lib/node/ParseUser.js | 1150 ++ lib/node/Push.js | 98 + lib/node/RESTController.js | 250 + lib/node/SingleInstanceStateController.js | 160 + lib/node/Storage.js | 93 + lib/node/StorageController.browser.js | 41 + lib/node/StorageController.default.js | 41 + lib/node/StorageController.react-native.js | 67 + lib/node/TaskQueue.js | 77 + lib/node/UniqueInstanceStateController.js | 189 + lib/node/arrayContainsObject.js | 35 + lib/node/canBeSerialized.js | 82 + lib/node/decode.js | 93 + lib/node/encode.js | 104 + lib/node/equals.js | 84 + lib/node/escape.js | 31 + lib/node/isRevocableSession.js | 20 + lib/node/parseDate.js | 34 + lib/node/unique.js | 45 + lib/node/unsavedChildren.js | 102 + lib/react-native/Analytics.js | 78 + lib/react-native/Cloud.js | 86 + lib/react-native/CoreManager.js | 188 + lib/react-native/EventEmitter.js | 16 + lib/react-native/FacebookUtils.js | 229 + lib/react-native/InstallationController.js | 54 + lib/react-native/LiveQueryClient.js | 430 + lib/react-native/LiveQuerySubscription.js | 112 + lib/react-native/ObjectStateMutations.js | 121 + lib/react-native/Parse.js | 141 + lib/react-native/ParseACL.js | 325 + lib/react-native/ParseConfig.js | 168 + lib/react-native/ParseError.js | 491 + lib/react-native/ParseFile.js | 247 + lib/react-native/ParseGeoPoint.js | 186 + lib/react-native/ParseHooks.js | 125 + lib/react-native/ParseInstallation.js | 25 + lib/react-native/ParseLiveQuery.js | 212 + lib/react-native/ParseObject.js | 1742 ++ lib/react-native/ParseOp.js | 434 + lib/react-native/ParsePromise.js | 575 + lib/react-native/ParseQuery.js | 1113 ++ lib/react-native/ParseRelation.js | 140 + lib/react-native/ParseRole.js | 133 + lib/react-native/ParseSession.js | 114 + lib/react-native/ParseUser.js | 952 ++ lib/react-native/Push.js | 77 + lib/react-native/RESTController.js | 226 + .../SingleInstanceStateController.js | 125 + lib/react-native/Storage.js | 92 + lib/react-native/StorageController.browser.js | 38 + lib/react-native/StorageController.default.js | 41 + .../StorageController.react-native.js | 60 + lib/react-native/TaskQueue.js | 53 + .../UniqueInstanceStateController.js | 140 + lib/react-native/arrayContainsObject.js | 24 + lib/react-native/canBeSerialized.js | 60 + lib/react-native/decode.js | 62 + lib/react-native/encode.js | 71 + lib/react-native/equals.js | 53 + lib/react-native/escape.js | 25 + lib/react-native/isRevocableSession.js | 14 + lib/react-native/parseDate.js | 28 + lib/react-native/unique.js | 29 + lib/react-native/unsavedChildren.js | 80 + 138 files changed, 47570 insertions(+), 2 deletions(-) create mode 100644 dist/parse.js create mode 100644 dist/parse.min.js create mode 100644 lib/browser/Analytics.js create mode 100644 lib/browser/Cloud.js create mode 100644 lib/browser/CoreManager.js create mode 100644 lib/browser/EventEmitter.js create mode 100644 lib/browser/FacebookUtils.js create mode 100644 lib/browser/InstallationController.js create mode 100644 lib/browser/LiveQueryClient.js create mode 100644 lib/browser/LiveQuerySubscription.js create mode 100644 lib/browser/ObjectStateMutations.js create mode 100644 lib/browser/Parse.js create mode 100644 lib/browser/ParseACL.js create mode 100644 lib/browser/ParseConfig.js create mode 100644 lib/browser/ParseError.js create mode 100644 lib/browser/ParseFile.js create mode 100644 lib/browser/ParseGeoPoint.js create mode 100644 lib/browser/ParseHooks.js create mode 100644 lib/browser/ParseInstallation.js create mode 100644 lib/browser/ParseLiveQuery.js create mode 100644 lib/browser/ParseObject.js create mode 100644 lib/browser/ParseOp.js create mode 100644 lib/browser/ParsePromise.js create mode 100644 lib/browser/ParseQuery.js create mode 100644 lib/browser/ParseRelation.js create mode 100644 lib/browser/ParseRole.js create mode 100644 lib/browser/ParseSession.js create mode 100644 lib/browser/ParseUser.js create mode 100644 lib/browser/Push.js create mode 100644 lib/browser/RESTController.js create mode 100644 lib/browser/SingleInstanceStateController.js create mode 100644 lib/browser/Storage.js create mode 100644 lib/browser/StorageController.browser.js create mode 100644 lib/browser/StorageController.default.js create mode 100644 lib/browser/StorageController.react-native.js create mode 100644 lib/browser/TaskQueue.js create mode 100644 lib/browser/UniqueInstanceStateController.js create mode 100644 lib/browser/arrayContainsObject.js create mode 100644 lib/browser/canBeSerialized.js create mode 100644 lib/browser/decode.js create mode 100644 lib/browser/encode.js create mode 100644 lib/browser/equals.js create mode 100644 lib/browser/escape.js create mode 100644 lib/browser/isRevocableSession.js create mode 100644 lib/browser/parseDate.js create mode 100644 lib/browser/unique.js create mode 100644 lib/browser/unsavedChildren.js create mode 100644 lib/node/Analytics.js create mode 100644 lib/node/Cloud.js create mode 100644 lib/node/CoreManager.js create mode 100644 lib/node/EventEmitter.js create mode 100644 lib/node/FacebookUtils.js create mode 100644 lib/node/InstallationController.js create mode 100644 lib/node/LiveQueryClient.js create mode 100644 lib/node/LiveQuerySubscription.js create mode 100644 lib/node/ObjectStateMutations.js create mode 100644 lib/node/Parse.js create mode 100644 lib/node/ParseACL.js create mode 100644 lib/node/ParseConfig.js create mode 100644 lib/node/ParseError.js create mode 100644 lib/node/ParseFile.js create mode 100644 lib/node/ParseGeoPoint.js create mode 100644 lib/node/ParseHooks.js create mode 100644 lib/node/ParseInstallation.js create mode 100644 lib/node/ParseLiveQuery.js create mode 100644 lib/node/ParseObject.js create mode 100644 lib/node/ParseOp.js create mode 100644 lib/node/ParsePromise.js create mode 100644 lib/node/ParseQuery.js create mode 100644 lib/node/ParseRelation.js create mode 100644 lib/node/ParseRole.js create mode 100644 lib/node/ParseSession.js create mode 100644 lib/node/ParseUser.js create mode 100644 lib/node/Push.js create mode 100644 lib/node/RESTController.js create mode 100644 lib/node/SingleInstanceStateController.js create mode 100644 lib/node/Storage.js create mode 100644 lib/node/StorageController.browser.js create mode 100644 lib/node/StorageController.default.js create mode 100644 lib/node/StorageController.react-native.js create mode 100644 lib/node/TaskQueue.js create mode 100644 lib/node/UniqueInstanceStateController.js create mode 100644 lib/node/arrayContainsObject.js create mode 100644 lib/node/canBeSerialized.js create mode 100644 lib/node/decode.js create mode 100644 lib/node/encode.js create mode 100644 lib/node/equals.js create mode 100644 lib/node/escape.js create mode 100644 lib/node/isRevocableSession.js create mode 100644 lib/node/parseDate.js create mode 100644 lib/node/unique.js create mode 100644 lib/node/unsavedChildren.js create mode 100644 lib/react-native/Analytics.js create mode 100644 lib/react-native/Cloud.js create mode 100644 lib/react-native/CoreManager.js create mode 100644 lib/react-native/EventEmitter.js create mode 100644 lib/react-native/FacebookUtils.js create mode 100644 lib/react-native/InstallationController.js create mode 100644 lib/react-native/LiveQueryClient.js create mode 100644 lib/react-native/LiveQuerySubscription.js create mode 100644 lib/react-native/ObjectStateMutations.js create mode 100644 lib/react-native/Parse.js create mode 100644 lib/react-native/ParseACL.js create mode 100644 lib/react-native/ParseConfig.js create mode 100644 lib/react-native/ParseError.js create mode 100644 lib/react-native/ParseFile.js create mode 100644 lib/react-native/ParseGeoPoint.js create mode 100644 lib/react-native/ParseHooks.js create mode 100644 lib/react-native/ParseInstallation.js create mode 100644 lib/react-native/ParseLiveQuery.js create mode 100644 lib/react-native/ParseObject.js create mode 100644 lib/react-native/ParseOp.js create mode 100644 lib/react-native/ParsePromise.js create mode 100644 lib/react-native/ParseQuery.js create mode 100644 lib/react-native/ParseRelation.js create mode 100644 lib/react-native/ParseRole.js create mode 100644 lib/react-native/ParseSession.js create mode 100644 lib/react-native/ParseUser.js create mode 100644 lib/react-native/Push.js create mode 100644 lib/react-native/RESTController.js create mode 100644 lib/react-native/SingleInstanceStateController.js create mode 100644 lib/react-native/Storage.js create mode 100644 lib/react-native/StorageController.browser.js create mode 100644 lib/react-native/StorageController.default.js create mode 100644 lib/react-native/StorageController.react-native.js create mode 100644 lib/react-native/TaskQueue.js create mode 100644 lib/react-native/UniqueInstanceStateController.js create mode 100644 lib/react-native/arrayContainsObject.js create mode 100644 lib/react-native/canBeSerialized.js create mode 100644 lib/react-native/decode.js create mode 100644 lib/react-native/encode.js create mode 100644 lib/react-native/equals.js create mode 100644 lib/react-native/escape.js create mode 100644 lib/react-native/isRevocableSession.js create mode 100644 lib/react-native/parseDate.js create mode 100644 lib/react-native/unique.js create mode 100644 lib/react-native/unsavedChildren.js diff --git a/.gitignore b/.gitignore index fcef25c5e..16a5fb13e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ coverage -dist -lib +#dist +#lib logs node_modules test_output diff --git a/dist/parse.js b/dist/parse.js new file mode 100644 index 000000000..1e049cfeb --- /dev/null +++ b/dist/parse.js @@ -0,0 +1,13937 @@ +/** + * Parse JavaScript SDK v1.9.2 + * + * The source tree of this library can be found at + * https://github.com/ParsePlatform/Parse-SDK-JS + */ +(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Parse = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o + * var dimensions = { + * gender: 'm', + * source: 'web', + * dayType: 'weekend' + * }; + * Parse.Analytics.track('signup', dimensions); + * + * + * There is a default limit of 8 dimensions per event tracked. + * + * @method track + * @param {String} name The name of the custom event to report to Parse as + * having happened. + * @param {Object} dimensions The dictionary of information by which to + * segment this event. + * @param {Object} options A Backbone-style callback object. + * @return {Parse.Promise} A promise that is resolved when the round-trip + * to the server completes. + */ +function track(name, dimensions, options) { + name = name || ''; + name = name.replace(/^\s*/, ''); + name = name.replace(/\s*$/, ''); + if (name.length === 0) { + throw new TypeError('A name for the custom event must be provided'); + } + + for (var key in dimensions) { + if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { + throw new TypeError('track() dimensions expects keys and values of type "string".'); + } + } + + options = options || {}; + return _CoreManager2.default.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var DefaultController = { + track: function (name, dimensions) { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); + } +}; + +_CoreManager2.default.setAnalyticsController(DefaultController); +},{"./CoreManager":3}],2:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = run; + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = _dereq_('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains functions for calling and declaring + * cloud functions. + *

+ * Some functions are only available from Cloud Code. + *

+ * + * @class Parse.Cloud + * @static + */ + +/** + * Makes a call to a cloud function. + * @method run + * @param {String} name The function name. + * @param {Object} data The parameters to send to the cloud function. + * @param {Object} options A Backbone-style options object + * options.success, if set, should be a function to handle a successful + * call to a cloud function. options.error should be a function that + * handles an error running the cloud function. Both functions are + * optional. Both functions take a single argument. + * @return {Parse.Promise} A promise that will be resolved with the result + * of the function. + */ +function run(name, data, options) { + options = options || {}; + + if (typeof name !== 'string' || name.length === 0) { + throw new TypeError('Cloud function name must be a string.'); + } + + var requestOptions = {}; + if (options.useMasterKey) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.sessionToken) { + requestOptions.sessionToken = options.sessionToken; + } + + return _CoreManager2.default.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var DefaultController = { + run: function (name, data, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + var payload = (0, _encode2.default)(data, true); + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + requestOptions.sessionToken = options.sessionToken; + } + + var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); + + return request.then(function (res) { + var decoded = (0, _decode2.default)(res); + if (decoded && decoded.hasOwnProperty('result')) { + return _ParsePromise2.default.as(decoded.result); + } + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); + })._thenRunCallbacks(options); + } +}; + +_CoreManager2.default.setCloudController(DefaultController); +},{"./CoreManager":3,"./ParseError":13,"./ParsePromise":20,"./decode":35,"./encode":36}],3:[function(_dereq_,module,exports){ +(function (process){ +'use strict'; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var config = { + // Defaults + IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, + REQUEST_ATTEMPT_LIMIT: 5, + SERVER_URL: 'https://api.parse.com/1', + LIVEQUERY_SERVER_URL: null, + VERSION: 'js' + '1.9.2', + APPLICATION_ID: null, + JAVASCRIPT_KEY: null, + MASTER_KEY: null, + USE_MASTER_KEY: false, + PERFORM_USER_REWRITE: true, + FORCE_REVOCABLE_SESSION: false +}; + +function requireMethods(name, methods, controller) { + methods.forEach(function (func) { + if (typeof controller[func] !== 'function') { + throw new Error(name + ' must implement ' + func + '()'); + } + }); +} + +module.exports = { + get: function (key) { + if (config.hasOwnProperty(key)) { + return config[key]; + } + throw new Error('Configuration key not found: ' + key); + }, + + set: function (key, value) { + config[key] = value; + }, + + /* Specialized Controller Setters/Getters */ + + setAnalyticsController: function (controller) { + requireMethods('AnalyticsController', ['track'], controller); + config['AnalyticsController'] = controller; + }, + getAnalyticsController: function () { + return config['AnalyticsController']; + }, + setCloudController: function (controller) { + requireMethods('CloudController', ['run'], controller); + config['CloudController'] = controller; + }, + getCloudController: function () { + return config['CloudController']; + }, + setConfigController: function (controller) { + requireMethods('ConfigController', ['current', 'get'], controller); + config['ConfigController'] = controller; + }, + getConfigController: function () { + return config['ConfigController']; + }, + setFileController: function (controller) { + requireMethods('FileController', ['saveFile', 'saveBase64'], controller); + config['FileController'] = controller; + }, + getFileController: function () { + return config['FileController']; + }, + setInstallationController: function (controller) { + requireMethods('InstallationController', ['currentInstallationId'], controller); + config['InstallationController'] = controller; + }, + getInstallationController: function () { + return config['InstallationController']; + }, + setObjectController: function (controller) { + requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); + config['ObjectController'] = controller; + }, + getObjectController: function () { + return config['ObjectController']; + }, + setObjectStateController: function (controller) { + requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); + + config['ObjectStateController'] = controller; + }, + getObjectStateController: function () { + return config['ObjectStateController']; + }, + setPushController: function (controller) { + requireMethods('PushController', ['send'], controller); + config['PushController'] = controller; + }, + getPushController: function () { + return config['PushController']; + }, + setQueryController: function (controller) { + requireMethods('QueryController', ['find'], controller); + config['QueryController'] = controller; + }, + getQueryController: function () { + return config['QueryController']; + }, + setRESTController: function (controller) { + requireMethods('RESTController', ['request', 'ajax'], controller); + config['RESTController'] = controller; + }, + getRESTController: function () { + return config['RESTController']; + }, + setSessionController: function (controller) { + requireMethods('SessionController', ['getSession'], controller); + config['SessionController'] = controller; + }, + getSessionController: function () { + return config['SessionController']; + }, + setStorageController: function (controller) { + if (controller.async) { + requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); + } else { + requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); + } + config['StorageController'] = controller; + }, + getStorageController: function () { + return config['StorageController']; + }, + setUserController: function (controller) { + requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); + config['UserController'] = controller; + }, + getUserController: function () { + return config['UserController']; + }, + setLiveQueryController: function (controller) { + requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); + config['LiveQueryController'] = controller; + }, + getLiveQueryController: function () { + return config['LiveQueryController']; + }, + setHooksController: function (controller) { + requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); + config['HooksController'] = controller; + }, + getHooksController: function () { + return config['HooksController']; + } +}; +}).call(this,_dereq_('_process')) +},{"_process":168}],4:[function(_dereq_,module,exports){ +'use strict'; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * This is a simple wrapper to unify EventEmitter implementations across platforms. + */ + +module.exports = _dereq_('events').EventEmitter; +var EventEmitter; +},{"events":169}],5:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _parseDate = _dereq_('./parseDate'); + +var _parseDate2 = _interopRequireDefault(_parseDate); + +var _ParseUser = _dereq_('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * -weak + */ + +var PUBLIC_KEY = "*"; + +var initialized = false; +var requestedPermissions; +var initOptions; +var provider = { + authenticate: function (options) { + var _this = this; + + if (typeof FB === 'undefined') { + options.error(this, 'Facebook SDK not found.'); + } + FB.login(function (response) { + if (response.authResponse) { + if (options.success) { + options.success(_this, { + id: response.authResponse.userID, + access_token: response.authResponse.accessToken, + expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() + }); + } + } else { + if (options.error) { + options.error(_this, response); + } + } + }, { + scope: requestedPermissions + }); + }, + restoreAuthentication: function (authData) { + if (authData) { + var expiration = (0, _parseDate2.default)(authData.expiration_date); + var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; + + var authResponse = { + userID: authData.id, + accessToken: authData.access_token, + expiresIn: expiresIn + }; + var newOptions = {}; + if (initOptions) { + for (var key in initOptions) { + newOptions[key] = initOptions[key]; + } + } + newOptions.authResponse = authResponse; + + // Suppress checks for login status from the browser. + newOptions.status = false; + + // If the user doesn't match the one known by the FB SDK, log out. + // Most of the time, the users will match -- it's only in cases where + // the FB SDK knows of a different user than the one being restored + // from a Parse User that logged in with username/password. + var existingResponse = FB.getAuthResponse(); + if (existingResponse && existingResponse.userID !== authResponse.userID) { + FB.logout(); + } + + FB.init(newOptions); + } + return true; + }, + getAuthType: function () { + return 'facebook'; + }, + deauthenticate: function () { + this.restoreAuthentication(null); + } +}; + +/** + * Provides a set of utilities for using Parse with Facebook. + * @class Parse.FacebookUtils + * @static + */ +var FacebookUtils = { + /** + * Initializes Parse Facebook integration. Call this function after you + * have loaded the Facebook Javascript SDK with the same parameters + * as you would pass to + * + * FB.init(). Parse.FacebookUtils will invoke FB.init() for you + * with these arguments. + * + * @method init + * @param {Object} options Facebook options argument as described here: + * + * FB.init(). The status flag will be coerced to 'false' because it + * interferes with Parse Facebook integration. Call FB.getLoginStatus() + * explicitly if this behavior is required by your application. + */ + init: function (options) { + if (typeof FB === 'undefined') { + throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); + } + initOptions = {}; + if (options) { + for (var key in options) { + initOptions[key] = options[key]; + } + } + if (initOptions.status && typeof console !== 'undefined') { + var warn = console.warn || console.log || function () {}; + warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); + } + initOptions.status = false; + FB.init(initOptions); + _ParseUser2.default._registerAuthenticationProvider(provider); + initialized = true; + }, + + /** + * Gets whether the user has their account linked to Facebook. + * + * @method isLinked + * @param {Parse.User} user User to check for a facebook link. + * The user must be logged in on this device. + * @return {Boolean} true if the user has their account + * linked to Facebook. + */ + isLinked: function (user) { + return user._isLinked('facebook'); + }, + + /** + * Logs in a user using Facebook. This method delegates to the Facebook + * SDK to authenticate the user, and then automatically logs in (or + * creates, in the case where it is a new user) a Parse.User. + * + * @method logIn + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + logIn: function (permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling logIn.'); + } + requestedPermissions = permissions; + return _ParseUser2.default._logInWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return _ParseUser2.default._logInWith('facebook', newOptions); + } + }, + + /** + * Links Facebook to an existing PFUser. This method delegates to the + * Facebook SDK to authenticate the user, and then automatically links + * the account to the Parse.User. + * + * @method link + * @param {Parse.User} user User to link to Facebook. This must be the + * current user. + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + link: function (user, permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling link.'); + } + requestedPermissions = permissions; + return user._linkWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return user._linkWith('facebook', newOptions); + } + }, + + /** + * Unlinks the Parse.User from a Facebook account. + * + * @method unlink + * @param {Parse.User} user User to unlink from Facebook. This must be the + * current user. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + unlink: function (user, options) { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling unlink.'); + } + return user._unlinkFrom('facebook', options); + } +}; + +exports.default = FacebookUtils; +},{"./ParseUser":25,"./parseDate":40}],6:[function(_dereq_,module,exports){ +'use strict'; + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = _dereq_('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var iidCache = null; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function hexOctet() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); +} + +function generateId() { + return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); +} + +var InstallationController = { + currentInstallationId: function () { + if (typeof iidCache === 'string') { + return _ParsePromise2.default.as(iidCache); + } + var path = _Storage2.default.generatePath('installationId'); + return _Storage2.default.getItemAsync(path).then(function (iid) { + if (!iid) { + iid = generateId(); + return _Storage2.default.setItemAsync(path, iid).then(function () { + iidCache = iid; + return iid; + }); + } + iidCache = iid; + return iid; + }); + }, + _clearCache: function () { + iidCache = null; + }, + _setInstallationIdCache: function (iid) { + iidCache = iid; + } +}; + +module.exports = InstallationController; +},{"./CoreManager":3,"./ParsePromise":20,"./Storage":29}],7:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getIterator2 = _dereq_('babel-runtime/core-js/get-iterator'); + +var _getIterator3 = _interopRequireDefault(_getIterator2); + +var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _map = _dereq_('babel-runtime/core-js/map'); + +var _map2 = _interopRequireDefault(_map); + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _EventEmitter2 = _dereq_('./EventEmitter'); + +var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _LiveQuerySubscription = _dereq_('./LiveQuerySubscription'); + +var _LiveQuerySubscription2 = _interopRequireDefault(_LiveQuerySubscription); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +// The LiveQuery client inner state +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +var CLIENT_STATE = { + INITIALIZED: 'initialized', + CONNECTING: 'connecting', + CONNECTED: 'connected', + CLOSED: 'closed', + RECONNECTING: 'reconnecting', + DISCONNECTED: 'disconnected' +}; + +// The event type the LiveQuery client should sent to server +var OP_TYPES = { + CONNECT: 'connect', + SUBSCRIBE: 'subscribe', + UNSUBSCRIBE: 'unsubscribe', + ERROR: 'error' +}; + +// The event we get back from LiveQuery server +var OP_EVENTS = { + CONNECTED: 'connected', + SUBSCRIBED: 'subscribed', + UNSUBSCRIBED: 'unsubscribed', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +// The event the LiveQuery client should emit +var CLIENT_EMMITER_TYPES = { + CLOSE: 'close', + ERROR: 'error', + OPEN: 'open' +}; + +// The event the LiveQuery subscription should emit +var SUBSCRIPTION_EMMITER_TYPES = { + OPEN: 'open', + CLOSE: 'close', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +var generateInterval = function (k) { + return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; +}; + +/** + * Creates a new LiveQueryClient. + * Extends events.EventEmitter + * cloud functions. + * + * A wrapper of a standard WebSocket client. We add several useful methods to + * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. + * + * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries + * to connect to the LiveQuery server + * + * @class Parse.LiveQueryClient + * @constructor + * @param {Object} options + * @param {string} options.applicationId - applicationId of your Parse app + * @param {string} options.serverURL - the URL of your LiveQuery server + * @param {string} options.javascriptKey (optional) + * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) + * @param {string} options.sessionToken (optional) + * + * + * We expose three events to help you monitor the status of the LiveQueryClient. + * + *
+ * let Parse = require('parse/node');
+ * let LiveQueryClient = Parse.LiveQueryClient;
+ * let client = new LiveQueryClient({
+ *   applicationId: '',
+ *   serverURL: '',
+ *   javascriptKey: '',
+ *   masterKey: ''
+ *  });
+ * 
+ * + * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + *
+ * client.on('open', () => {
+ * 
+ * });
+ * + * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + *
+ * client.on('close', () => {
+ * 
+ * });
+ * + * Error - When some network error or LiveQuery server error happens, you'll get this event. + *
+ * client.on('error', (error) => {
+ * 
+ * });
+ * + * + */ + +var LiveQueryClient = function (_EventEmitter) { + (0, _inherits3.default)(LiveQueryClient, _EventEmitter); + + function LiveQueryClient(_ref) { + var applicationId = _ref.applicationId, + serverURL = _ref.serverURL, + javascriptKey = _ref.javascriptKey, + masterKey = _ref.masterKey, + sessionToken = _ref.sessionToken; + (0, _classCallCheck3.default)(this, LiveQueryClient); + + var _this = (0, _possibleConstructorReturn3.default)(this, (LiveQueryClient.__proto__ || (0, _getPrototypeOf2.default)(LiveQueryClient)).call(this)); + + if (!serverURL || serverURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + _this.reconnectHandle = null; + _this.attempts = 1;; + _this.id = 0; + _this.requestId = 1; + _this.serverURL = serverURL; + _this.applicationId = applicationId; + _this.javascriptKey = javascriptKey; + _this.masterKey = masterKey; + _this.sessionToken = sessionToken; + _this.connectPromise = new _ParsePromise2.default(); + _this.subscriptions = new _map2.default(); + _this.state = CLIENT_STATE.INITIALIZED; + return _this; + } + + (0, _createClass3.default)(LiveQueryClient, [{ + key: 'shouldOpen', + value: function () { + return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; + } + + /** + * Subscribes to a ParseQuery + * + * If you provide the sessionToken, when the LiveQuery server gets ParseObject's + * updates from parse server, it'll try to check whether the sessionToken fulfills + * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose + * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol + * here for more details. The subscription you get is the same subscription you get + * from our Standard API. + * + * @method subscribe + * @param {Object} query - the ParseQuery you want to subscribe to + * @param {string} sessionToken (optional) + * @return {Object} subscription + */ + + }, { + key: 'subscribe', + value: function (query, sessionToken) { + var _this2 = this; + + if (!query) { + return; + } + var where = query.toJSON().where; + var className = query.className; + var subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: this.requestId, + query: { + className: className, + where: where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + var subscription = new _LiveQuerySubscription2.default(this.requestId, query, sessionToken); + this.subscriptions.set(this.requestId, subscription); + this.requestId += 1; + this.connectPromise.then(function () { + _this2.socket.send((0, _stringify2.default)(subscribeRequest)); + }); + + // adding listener so process does not crash + // best practice is for developer to register their own listener + subscription.on('error', function () {}); + + return subscription; + } + + /** + * After calling unsubscribe you'll stop receiving events from the subscription object. + * + * @method unsubscribe + * @param {Object} subscription - subscription you would like to unsubscribe from. + */ + + }, { + key: 'unsubscribe', + value: function (subscription) { + var _this3 = this; + + if (!subscription) { + return; + } + + this.subscriptions.delete(subscription.id); + var unsubscribeRequest = { + op: OP_TYPES.UNSUBSCRIBE, + requestId: subscription.id + }; + this.connectPromise.then(function () { + _this3.socket.send((0, _stringify2.default)(unsubscribeRequest)); + }); + } + + /** + * After open is called, the LiveQueryClient will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ + + }, { + key: 'open', + value: function () { + var _this4 = this; + + var WebSocketImplementation = this._getWebSocketImplementation(); + if (!WebSocketImplementation) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); + return; + } + + if (this.state !== CLIENT_STATE.RECONNECTING) { + this.state = CLIENT_STATE.CONNECTING; + } + + // Get WebSocket implementation + this.socket = new WebSocketImplementation(this.serverURL); + + // Bind WebSocket callbacks + this.socket.onopen = function () { + _this4._handleWebSocketOpen(); + }; + + this.socket.onmessage = function (event) { + _this4._handleWebSocketMessage(event); + }; + + this.socket.onclose = function () { + _this4._handleWebSocketClose(); + }; + + this.socket.onerror = function (error) { + _this4._handleWebSocketError(error); + }; + } + }, { + key: 'resubscribe', + value: function () { + var _this5 = this; + + this.subscriptions.forEach(function (subscription, requestId) { + var query = subscription.query; + var where = query.toJSON().where; + var className = query.className; + var sessionToken = subscription.sessionToken; + var subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: requestId, + query: { + className: className, + where: where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + _this5.connectPromise.then(function () { + _this5.socket.send((0, _stringify2.default)(subscribeRequest)); + }); + }); + } + + /** + * This method will close the WebSocket connection to this LiveQueryClient, + * cancel the auto reconnect and unsubscribe all subscriptions based on it. + * + * @method close + */ + + }, { + key: 'close', + value: function () { + if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.DISCONNECTED; + this.socket.close(); + // Notify each subscription about the close + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = (0, _getIterator3.default)(this.subscriptions.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var subscription = _step.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + this._handleReset(); + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + } + }, { + key: '_getWebSocketImplementation', + value: function () { + return typeof WebSocket === 'function' || (typeof WebSocket === 'undefined' ? 'undefined' : (0, _typeof3.default)(WebSocket)) === 'object' ? WebSocket : null; + } + + // ensure we start with valid state if connect is called again after close + + }, { + key: '_handleReset', + value: function () { + this.attempts = 1;; + this.id = 0; + this.requestId = 1; + this.connectPromise = new _ParsePromise2.default(); + this.subscriptions = new _map2.default(); + } + }, { + key: '_handleWebSocketOpen', + value: function () { + this.attempts = 1; + var connectRequest = { + op: OP_TYPES.CONNECT, + applicationId: this.applicationId, + javascriptKey: this.javascriptKey, + masterKey: this.masterKey, + sessionToken: this.sessionToken + }; + this.socket.send((0, _stringify2.default)(connectRequest)); + } + }, { + key: '_handleWebSocketMessage', + value: function (event) { + var data = event.data; + if (typeof data === 'string') { + data = JSON.parse(data); + } + var subscription = null; + if (data.requestId) { + subscription = this.subscriptions.get(data.requestId); + } + switch (data.op) { + case OP_EVENTS.CONNECTED: + if (this.state === CLIENT_STATE.RECONNECTING) { + this.resubscribe(); + } + this.emit(CLIENT_EMMITER_TYPES.OPEN); + this.id = data.clientId; + this.connectPromise.resolve(); + this.state = CLIENT_STATE.CONNECTED; + break; + case OP_EVENTS.SUBSCRIBED: + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); + } + break; + case OP_EVENTS.ERROR: + if (data.requestId) { + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); + } + } else { + this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); + } + break; + case OP_EVENTS.UNSUBSCRIBED: + // We have already deleted subscription in unsubscribe(), do nothing here + break; + default: + // create, update, enter, leave, delete cases + var className = data.object.className; + // Delete the extrea __type and className fields during transfer to full JSON + delete data.object.__type; + delete data.object.className; + var parseObject = new _ParseObject2.default(className); + parseObject._finishFetch(data.object); + if (!subscription) { + break; + } + subscription.emit(data.op, parseObject); + } + } + }, { + key: '_handleWebSocketClose', + value: function () { + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.CLOSED; + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + // Notify each subscription about the close + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = (0, _getIterator3.default)(this.subscriptions.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var subscription = _step2.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + this._handleReconnect(); + } + }, { + key: '_handleWebSocketError', + value: function (error) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, error); + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = (0, _getIterator3.default)(this.subscriptions.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var subscription = _step3.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + this._handleReconnect(); + } + }, { + key: '_handleReconnect', + value: function () { + var _this6 = this; + + // if closed or currently reconnecting we stop attempting to reconnect + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + + this.state = CLIENT_STATE.RECONNECTING; + var time = generateInterval(this.attempts); + + // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. + // we're unable to distinguish different between close/error when we're unable to reconnect therefore + // we try to reonnect in both cases + // server side ws and browser WebSocket behave differently in when close/error get triggered + + if (this.reconnectHandle) { + clearTimeout(this.reconnectHandle); + } + + this.reconnectHandle = setTimeout(function () { + _this6.attempts++; + _this6.connectPromise = new _ParsePromise2.default(); + _this6.open(); + }.bind(this), time); + } + }]); + return LiveQueryClient; +}(_EventEmitter3.default); + +exports.default = LiveQueryClient; +},{"./EventEmitter":4,"./LiveQuerySubscription":8,"./ParseObject":18,"./ParsePromise":20,"babel-runtime/core-js/get-iterator":43,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/map":45,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],8:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _EventEmitter2 = _dereq_('./EventEmitter'); + +var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new LiveQuery Subscription. + * Extends events.EventEmitter + * cloud functions. + * + * @constructor + * @param {string} id - subscription id + * @param {string} query - query to subscribe to + * @param {string} sessionToken - optional session token + * + *

Open Event - When you call query.subscribe(), we send a subscribe request to + * the LiveQuery server, when we get the confirmation from the LiveQuery server, + * this event will be emitted. When the client loses WebSocket connection to the + * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we + * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, + * you'll also get this event. + * + *

+ * subscription.on('open', () => {
+ * 
+ * });

+ * + *

Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, + * you'll get this event. The object is the ParseObject which is created. + * + *

+ * subscription.on('create', (object) => {
+ * 
+ * });

+ * + *

Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe + * is updated (The ParseObject fulfills the ParseQuery before and after changes), + * you'll get this event. The object is the ParseObject which is updated. + * Its content is the latest value of the ParseObject. + * + *

+ * subscription.on('update', (object) => {
+ * 
+ * });

+ * + *

Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery + * but its new value fulfills the ParseQuery, you'll get this event. The object is the + * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. + * + *

+ * subscription.on('enter', (object) => {
+ * 
+ * });

+ * + * + *

Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value + * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject + * which leaves the ParseQuery. Its content is the latest value of the ParseObject. + * + *

+ * subscription.on('leave', (object) => {
+ * 
+ * });

+ * + * + *

Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll + * get this event. The object is the ParseObject which is deleted. + * + *

+ * subscription.on('delete', (object) => {
+ * 
+ * });

+ * + * + *

Close Event - When the client loses the WebSocket connection to the LiveQuery + * server and we stop receiving events, you'll get this event. + * + *

+ * subscription.on('close', () => {
+ * 
+ * });

+ * + * + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +var Subscription = function (_EventEmitter) { + (0, _inherits3.default)(Subscription, _EventEmitter); + + function Subscription(id, query, sessionToken) { + (0, _classCallCheck3.default)(this, Subscription); + + var _this2 = (0, _possibleConstructorReturn3.default)(this, (Subscription.__proto__ || (0, _getPrototypeOf2.default)(Subscription)).call(this)); + + _this2.id = id; + _this2.query = query; + _this2.sessionToken = sessionToken; + return _this2; + } + + /** + * @method unsubscribe + */ + + (0, _createClass3.default)(Subscription, [{ + key: 'unsubscribe', + value: function () { + var _this3 = this; + + var _this = this; + _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient().then(function (liveQueryClient) { + liveQueryClient.unsubscribe(_this); + _this.emit('close'); + _this3.resolve(); + }); + } + }]); + return Subscription; +}(_EventEmitter3.default); + +exports.default = Subscription; +},{"./CoreManager":3,"./EventEmitter":4,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],9:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.defaultState = defaultState; +exports.setServerData = setServerData; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _TaskQueue = _dereq_('./TaskQueue'); + +var _TaskQueue2 = _interopRequireDefault(_TaskQueue); + +var _ParseOp = _dereq_('./ParseOp'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function defaultState() { + return { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new _TaskQueue2.default(), + existed: false + }; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function setServerData(serverData, attributes) { + for (var _attr in attributes) { + if (typeof attributes[_attr] !== 'undefined') { + serverData[_attr] = attributes[_attr]; + } else { + delete serverData[_attr]; + } + } +} + +function setPendingOp(pendingOps, attr, op) { + var last = pendingOps.length - 1; + if (op) { + pendingOps[last][attr] = op; + } else { + delete pendingOps[last][attr]; + } +} + +function pushPendingState(pendingOps) { + pendingOps.push({}); +} + +function popPendingState(pendingOps) { + var first = pendingOps.shift(); + if (!pendingOps.length) { + pendingOps[0] = {}; + } + return first; +} + +function mergeFirstPendingState(pendingOps) { + var first = popPendingState(pendingOps); + var next = pendingOps[0]; + for (var _attr2 in first) { + if (next[_attr2] && first[_attr2]) { + var merged = next[_attr2].mergeWith(first[_attr2]); + if (merged) { + next[_attr2] = merged; + } + } else { + next[_attr2] = first[_attr2]; + } + } +} + +function estimateAttribute(serverData, pendingOps, className, id, attr) { + var value = serverData[attr]; + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i][attr]) { + if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { + if (id) { + value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); + } + } else { + value = pendingOps[i][attr].applyTo(value); + } + } + } + return value; +} + +function estimateAttributes(serverData, pendingOps, className, id) { + var data = {}; + var attr = void 0; + for (attr in serverData) { + data[attr] = serverData[attr]; + } + for (var i = 0; i < pendingOps.length; i++) { + for (attr in pendingOps[i]) { + if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { + if (id) { + data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); + } + } else { + data[attr] = pendingOps[i][attr].applyTo(data[attr]); + } + } + } + return data; +} + +function commitServerChanges(serverData, objectCache, changes) { + for (var _attr3 in changes) { + var val = changes[_attr3]; + serverData[_attr3] = val; + if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof _ParseObject2.default) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { + var json = (0, _encode2.default)(val, false, true); + objectCache[_attr3] = (0, _stringify2.default)(json); + } + } +} +},{"./ParseFile":14,"./ParseObject":18,"./ParseOp":19,"./ParsePromise":20,"./ParseRelation":22,"./TaskQueue":31,"./encode":36,"babel-runtime/core-js/json/stringify":44,"babel-runtime/helpers/typeof":61}],10:[function(_dereq_,module,exports){ +'use strict'; + +var _decode = _dereq_('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _InstallationController = _dereq_('./InstallationController'); + +var _InstallationController2 = _interopRequireDefault(_InstallationController); + +var _ParseOp = _dereq_('./ParseOp'); + +var ParseOp = _interopRequireWildcard(_ParseOp); + +var _RESTController = _dereq_('./RESTController'); + +var _RESTController2 = _interopRequireDefault(_RESTController); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains all Parse API classes and functions. + * @class Parse + * @static + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var Parse = { + /** + * Call this method first to set up your authentication tokens for Parse. + * You can get your keys from the Data Browser on parse.com. + * @method initialize + * @param {String} applicationId Your Parse Application ID. + * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) + * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) + * @static + */ + initialize: function (applicationId, javaScriptKey) { + if ('browser' === 'browser' && _CoreManager2.default.get('IS_NODE')) { + console.log('It looks like you\'re using the browser version of the SDK in a ' + 'node.js environment. You should require(\'parse/node\') instead.'); + } + Parse._initialize(applicationId, javaScriptKey); + }, + _initialize: function (applicationId, javaScriptKey, masterKey) { + _CoreManager2.default.set('APPLICATION_ID', applicationId); + _CoreManager2.default.set('JAVASCRIPT_KEY', javaScriptKey); + _CoreManager2.default.set('MASTER_KEY', masterKey); + _CoreManager2.default.set('USE_MASTER_KEY', false); + } +}; + +/** These legacy setters may eventually be deprecated **/ +Object.defineProperty(Parse, 'applicationId', { + get: function () { + return _CoreManager2.default.get('APPLICATION_ID'); + }, + set: function (value) { + _CoreManager2.default.set('APPLICATION_ID', value); + } +}); +Object.defineProperty(Parse, 'javaScriptKey', { + get: function () { + return _CoreManager2.default.get('JAVASCRIPT_KEY'); + }, + set: function (value) { + _CoreManager2.default.set('JAVASCRIPT_KEY', value); + } +}); +Object.defineProperty(Parse, 'masterKey', { + get: function () { + return _CoreManager2.default.get('MASTER_KEY'); + }, + set: function (value) { + _CoreManager2.default.set('MASTER_KEY', value); + } +}); +Object.defineProperty(Parse, 'serverURL', { + get: function () { + return _CoreManager2.default.get('SERVER_URL'); + }, + set: function (value) { + _CoreManager2.default.set('SERVER_URL', value); + } +}); +Object.defineProperty(Parse, 'liveQueryServerURL', { + get: function () { + return _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); + }, + set: function (value) { + _CoreManager2.default.set('LIVEQUERY_SERVER_URL', value); + } +}); +/** End setters **/ + +Parse.ACL = _dereq_('./ParseACL').default; +Parse.Analytics = _dereq_('./Analytics'); +Parse.Cloud = _dereq_('./Cloud'); +Parse.CoreManager = _dereq_('./CoreManager'); +Parse.Config = _dereq_('./ParseConfig').default; +Parse.Error = _dereq_('./ParseError').default; +Parse.FacebookUtils = _dereq_('./FacebookUtils').default; +Parse.File = _dereq_('./ParseFile').default; +Parse.GeoPoint = _dereq_('./ParseGeoPoint').default; +Parse.Installation = _dereq_('./ParseInstallation').default; +Parse.Object = _dereq_('./ParseObject').default; +Parse.Op = { + Set: ParseOp.SetOp, + Unset: ParseOp.UnsetOp, + Increment: ParseOp.IncrementOp, + Add: ParseOp.AddOp, + Remove: ParseOp.RemoveOp, + AddUnique: ParseOp.AddUniqueOp, + Relation: ParseOp.RelationOp +}; +Parse.Promise = _dereq_('./ParsePromise').default; +Parse.Push = _dereq_('./Push'); +Parse.Query = _dereq_('./ParseQuery').default; +Parse.Relation = _dereq_('./ParseRelation').default; +Parse.Role = _dereq_('./ParseRole').default; +Parse.Session = _dereq_('./ParseSession').default; +Parse.Storage = _dereq_('./Storage'); +Parse.User = _dereq_('./ParseUser').default; +Parse.LiveQuery = _dereq_('./ParseLiveQuery').default; +Parse.LiveQueryClient = _dereq_('./LiveQueryClient').default; + +Parse._request = function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return _CoreManager2.default.getRESTController().request.apply(null, args); +}; +Parse._ajax = function () { + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return _CoreManager2.default.getRESTController().ajax.apply(null, args); +}; +// We attempt to match the signatures of the legacy versions of these methods +Parse._decode = function (_, value) { + return (0, _decode2.default)(value); +}; +Parse._encode = function (value, _, disallowObjects) { + return (0, _encode2.default)(value, disallowObjects); +}; +Parse._getInstallationId = function () { + return _CoreManager2.default.getInstallationController().currentInstallationId(); +}; + +_CoreManager2.default.setInstallationController(_InstallationController2.default); +_CoreManager2.default.setRESTController(_RESTController2.default); + +// For legacy requires, of the form `var Parse = require('parse').Parse` +Parse.Parse = Parse; + +module.exports = Parse; +},{"./Analytics":1,"./Cloud":2,"./CoreManager":3,"./FacebookUtils":5,"./InstallationController":6,"./LiveQueryClient":7,"./ParseACL":11,"./ParseConfig":12,"./ParseError":13,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseInstallation":16,"./ParseLiveQuery":17,"./ParseObject":18,"./ParseOp":19,"./ParsePromise":20,"./ParseQuery":21,"./ParseRelation":22,"./ParseRole":23,"./ParseSession":24,"./ParseUser":25,"./Push":26,"./RESTController":27,"./Storage":29,"./decode":35,"./encode":36}],11:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _keys = _dereq_('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParseRole = _dereq_('./ParseRole'); + +var _ParseRole2 = _interopRequireDefault(_ParseRole); + +var _ParseUser = _dereq_('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var PUBLIC_KEY = '*'; + +/** + * Creates a new ACL. + * If no argument is given, the ACL has no permissions for anyone. + * If the argument is a Parse.User, the ACL will have read and write + * permission for only that user. + * If the argument is any other JSON object, that object will be interpretted + * as a serialized ACL created with toJSON(). + * @class Parse.ACL + * @constructor + * + *

An ACL, or Access Control List can be added to any + * Parse.Object to restrict access to only a subset of users + * of your application.

+ */ + +var ParseACL = function () { + function ParseACL(arg1) { + (0, _classCallCheck3.default)(this, ParseACL); + + this.permissionsById = {}; + if (arg1 && (typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { + if (arg1 instanceof _ParseUser2.default) { + this.setReadAccess(arg1, true); + this.setWriteAccess(arg1, true); + } else { + for (var userId in arg1) { + var accessList = arg1[userId]; + if (typeof userId !== 'string') { + throw new TypeError('Tried to create an ACL with an invalid user id.'); + } + this.permissionsById[userId] = {}; + for (var permission in accessList) { + var allowed = accessList[permission]; + if (permission !== 'read' && permission !== 'write') { + throw new TypeError('Tried to create an ACL with an invalid permission type.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('Tried to create an ACL with an invalid permission value.'); + } + this.permissionsById[userId][permission] = allowed; + } + } + } + } else if (typeof arg1 === 'function') { + throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); + } + } + + /** + * Returns a JSON-encoded version of the ACL. + * @method toJSON + * @return {Object} + */ + + (0, _createClass3.default)(ParseACL, [{ + key: 'toJSON', + value: function () { + var permissions = {}; + for (var p in this.permissionsById) { + permissions[p] = this.permissionsById[p]; + } + return permissions; + } + + /** + * Returns whether this ACL is equal to another object + * @method equals + * @param other The other object to compare to + * @return {Boolean} + */ + + }, { + key: 'equals', + value: function (other) { + if (!(other instanceof ParseACL)) { + return false; + } + var users = (0, _keys2.default)(this.permissionsById); + var otherUsers = (0, _keys2.default)(other.permissionsById); + if (users.length !== otherUsers.length) { + return false; + } + for (var u in this.permissionsById) { + if (!other.permissionsById[u]) { + return false; + } + if (this.permissionsById[u].read !== other.permissionsById[u].read) { + return false; + } + if (this.permissionsById[u].write !== other.permissionsById[u].write) { + return false; + } + } + return true; + } + }, { + key: '_setAccess', + value: function (accessType, userId, allowed) { + if (userId instanceof _ParseUser2.default) { + userId = userId.id; + } else if (userId instanceof _ParseRole2.default) { + var name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + if (typeof userId !== 'string') { + throw new TypeError('userId must be a string.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('allowed must be either true or false.'); + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + if (!allowed) { + // The user already doesn't have this permission, so no action is needed + return; + } else { + permissions = {}; + this.permissionsById[userId] = permissions; + } + } + + if (allowed) { + this.permissionsById[userId][accessType] = true; + } else { + delete permissions[accessType]; + if ((0, _keys2.default)(permissions).length === 0) { + delete this.permissionsById[userId]; + } + } + } + }, { + key: '_getAccess', + value: function (accessType, userId) { + if (userId instanceof _ParseUser2.default) { + userId = userId.id; + if (!userId) { + throw new Error('Cannot get access for a ParseUser without an ID'); + } + } else if (userId instanceof _ParseRole2.default) { + var name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + return false; + } + return !!permissions[accessType]; + } + + /** + * Sets whether the given user is allowed to read this object. + * @method setReadAccess + * @param userId An instance of Parse.User or its objectId. + * @param {Boolean} allowed Whether that user should have read access. + */ + + }, { + key: 'setReadAccess', + value: function (userId, allowed) { + this._setAccess('read', userId, allowed); + } + + /** + * Get whether the given user id is *explicitly* allowed to read this object. + * Even if this returns false, the user may still be able to access it if + * getPublicReadAccess returns true or a role that the user belongs to has + * write access. + * @method getReadAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + + }, { + key: 'getReadAccess', + value: function (userId) { + return this._getAccess('read', userId); + } + + /** + * Sets whether the given user id is allowed to write this object. + * @method setWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. + * @param {Boolean} allowed Whether that user should have write access. + */ + + }, { + key: 'setWriteAccess', + value: function (userId, allowed) { + this._setAccess('write', userId, allowed); + } + + /** + * Gets whether the given user id is *explicitly* allowed to write this object. + * Even if this returns false, the user may still be able to write it if + * getPublicWriteAccess returns true or a role that the user belongs to has + * write access. + * @method getWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + + }, { + key: 'getWriteAccess', + value: function (userId) { + return this._getAccess('write', userId); + } + + /** + * Sets whether the public is allowed to read this object. + * @method setPublicReadAccess + * @param {Boolean} allowed + */ + + }, { + key: 'setPublicReadAccess', + value: function (allowed) { + this.setReadAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to read this object. + * @method getPublicReadAccess + * @return {Boolean} + */ + + }, { + key: 'getPublicReadAccess', + value: function () { + return this.getReadAccess(PUBLIC_KEY); + } + + /** + * Sets whether the public is allowed to write this object. + * @method setPublicWriteAccess + * @param {Boolean} allowed + */ + + }, { + key: 'setPublicWriteAccess', + value: function (allowed) { + this.setWriteAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to write this object. + * @method getPublicWriteAccess + * @return {Boolean} + */ + + }, { + key: 'getPublicWriteAccess', + value: function () { + return this.getWriteAccess(PUBLIC_KEY); + } + + /** + * Gets whether users belonging to the given role are allowed + * to read this object. Even if this returns false, the role may + * still be able to write it if a parent role has read access. + * + * @method getRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has read access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'getRoleReadAccess', + value: function (role) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getReadAccess('role:' + role); + } + + /** + * Gets whether users belonging to the given role are allowed + * to write this object. Even if this returns false, the role may + * still be able to write it if a parent role has write access. + * + * @method getRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has write access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'getRoleWriteAccess', + value: function (role) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getWriteAccess('role:' + role); + } + + /** + * Sets whether users belonging to the given role are allowed + * to read this object. + * + * @method setRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can read this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'setRoleReadAccess', + value: function (role, allowed) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setReadAccess('role:' + role, allowed); + } + + /** + * Sets whether users belonging to the given role are allowed + * to write this object. + * + * @method setRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can write this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'setRoleWriteAccess', + value: function (role, allowed) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setWriteAccess('role:' + role, allowed); + } + }]); + return ParseACL; +}(); + +exports.default = ParseACL; +},{"./ParseRole":23,"./ParseUser":25,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],12:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = _dereq_('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _escape2 = _dereq_('./escape'); + +var _escape3 = _interopRequireDefault(_escape2); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = _dereq_('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Parse.Config is a local representation of configuration data that + * can be set from the Parse dashboard. + * + * @class Parse.Config + * @constructor + */ + +var ParseConfig = function () { + function ParseConfig() { + (0, _classCallCheck3.default)(this, ParseConfig); + + this.attributes = {}; + this._escapedAttributes = {}; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The name of an attribute. + */ + + (0, _createClass3.default)(ParseConfig, [{ + key: 'get', + value: function (attr) { + return this.attributes[attr]; + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The name of an attribute. + */ + + }, { + key: 'escape', + value: function (attr) { + var html = this._escapedAttributes[attr]; + if (html) { + return html; + } + var val = this.attributes[attr]; + var escaped = ''; + if (val != null) { + escaped = (0, _escape3.default)(val.toString()); + } + this._escapedAttributes[attr] = escaped; + return escaped; + } + + /** + * Retrieves the most recently-fetched configuration object, either from + * memory or from local storage if necessary. + * + * @method current + * @static + * @return {Config} The most recently-fetched Parse.Config if it + * exists, else an empty Parse.Config. + */ + + }], [{ + key: 'current', + value: function () { + var controller = _CoreManager2.default.getConfigController(); + return controller.current(); + } + + /** + * Gets a new configuration object from the server. + * @method get + * @static + * @param {Object} options A Backbone-style options object. + * Valid options are:
    + *
  • success: Function to call when the get completes successfully. + *
  • error: Function to call when the get fails. + *
+ * @return {Parse.Promise} A promise that is resolved with a newly-created + * configuration object when the get completes. + */ + + }, { + key: 'get', + value: function (options) { + options = options || {}; + + var controller = _CoreManager2.default.getConfigController(); + return controller.get()._thenRunCallbacks(options); + } + }]); + return ParseConfig; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseConfig; + +var currentConfig = null; + +var CURRENT_CONFIG_KEY = 'currentConfig'; + +function decodePayload(data) { + try { + var json = JSON.parse(data); + if (json && (typeof json === 'undefined' ? 'undefined' : (0, _typeof3.default)(json)) === 'object') { + return (0, _decode2.default)(json); + } + } catch (e) { + return null; + } +} + +var DefaultController = { + current: function () { + if (currentConfig) { + return currentConfig; + } + + var config = new ParseConfig(); + var storagePath = _Storage2.default.generatePath(CURRENT_CONFIG_KEY); + var configData; + if (!_Storage2.default.async()) { + configData = _Storage2.default.getItem(storagePath); + + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + } + // Return a promise for async storage controllers + return _Storage2.default.getItemAsync(storagePath).then(function (configData) { + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + }); + }, + get: function () { + var RESTController = _CoreManager2.default.getRESTController(); + + return RESTController.request('GET', 'config', {}, {}).then(function (response) { + if (!response || !response.params) { + var error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Config JSON response invalid.'); + return _ParsePromise2.default.error(error); + } + + var config = new ParseConfig(); + config.attributes = {}; + for (var attr in response.params) { + config.attributes[attr] = (0, _decode2.default)(response.params[attr]); + } + currentConfig = config; + return _Storage2.default.setItemAsync(_Storage2.default.generatePath(CURRENT_CONFIG_KEY), (0, _stringify2.default)(response.params)).then(function () { + return config; + }); + }); + } +}; + +_CoreManager2.default.setConfigController(DefaultController); +},{"./CoreManager":3,"./ParseError":13,"./ParsePromise":20,"./Storage":29,"./decode":35,"./encode":36,"./escape":38,"babel-runtime/core-js/json/stringify":44,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],13:[function(_dereq_,module,exports){ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck"); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * Constructs a new Parse.Error object with the given code and message. + * @class Parse.Error + * @constructor + * @param {Number} code An error code constant from Parse.Error. + * @param {String} message A detailed description of the error. + */ +var ParseError = function ParseError(code, message) { + (0, _classCallCheck3.default)(this, ParseError); + + this.code = code; + this.message = message; +}; + +/** + * Error code indicating some error other than those enumerated here. + * @property OTHER_CAUSE + * @static + * @final + */ + +exports.default = ParseError; +ParseError.OTHER_CAUSE = -1; + +/** + * Error code indicating that something has gone wrong with the server. + * If you get this error code, it is Parse's fault. Contact us at + * https://parse.com/help + * @property INTERNAL_SERVER_ERROR + * @static + * @final + */ +ParseError.INTERNAL_SERVER_ERROR = 1; + +/** + * Error code indicating the connection to the Parse servers failed. + * @property CONNECTION_FAILED + * @static + * @final + */ +ParseError.CONNECTION_FAILED = 100; + +/** + * Error code indicating the specified object doesn't exist. + * @property OBJECT_NOT_FOUND + * @static + * @final + */ +ParseError.OBJECT_NOT_FOUND = 101; + +/** + * Error code indicating you tried to query with a datatype that doesn't + * support it, like exact matching an array or object. + * @property INVALID_QUERY + * @static + * @final + */ +ParseError.INVALID_QUERY = 102; + +/** + * Error code indicating a missing or invalid classname. Classnames are + * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the + * only valid characters. + * @property INVALID_CLASS_NAME + * @static + * @final + */ +ParseError.INVALID_CLASS_NAME = 103; + +/** + * Error code indicating an unspecified object id. + * @property MISSING_OBJECT_ID + * @static + * @final + */ +ParseError.MISSING_OBJECT_ID = 104; + +/** + * Error code indicating an invalid key name. Keys are case-sensitive. They + * must start with a letter, and a-zA-Z0-9_ are the only valid characters. + * @property INVALID_KEY_NAME + * @static + * @final + */ +ParseError.INVALID_KEY_NAME = 105; + +/** + * Error code indicating a malformed pointer. You should not see this unless + * you have been mucking about changing internal Parse code. + * @property INVALID_POINTER + * @static + * @final + */ +ParseError.INVALID_POINTER = 106; + +/** + * Error code indicating that badly formed JSON was received upstream. This + * either indicates you have done something unusual with modifying how + * things encode to JSON, or the network is failing badly. + * @property INVALID_JSON + * @static + * @final + */ +ParseError.INVALID_JSON = 107; + +/** + * Error code indicating that the feature you tried to access is only + * available internally for testing purposes. + * @property COMMAND_UNAVAILABLE + * @static + * @final + */ +ParseError.COMMAND_UNAVAILABLE = 108; + +/** + * You must call Parse.initialize before using the Parse library. + * @property NOT_INITIALIZED + * @static + * @final + */ +ParseError.NOT_INITIALIZED = 109; + +/** + * Error code indicating that a field was set to an inconsistent type. + * @property INCORRECT_TYPE + * @static + * @final + */ +ParseError.INCORRECT_TYPE = 111; + +/** + * Error code indicating an invalid channel name. A channel name is either + * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ + * characters and starts with a letter. + * @property INVALID_CHANNEL_NAME + * @static + * @final + */ +ParseError.INVALID_CHANNEL_NAME = 112; + +/** + * Error code indicating that push is misconfigured. + * @property PUSH_MISCONFIGURED + * @static + * @final + */ +ParseError.PUSH_MISCONFIGURED = 115; + +/** + * Error code indicating that the object is too large. + * @property OBJECT_TOO_LARGE + * @static + * @final + */ +ParseError.OBJECT_TOO_LARGE = 116; + +/** + * Error code indicating that the operation isn't allowed for clients. + * @property OPERATION_FORBIDDEN + * @static + * @final + */ +ParseError.OPERATION_FORBIDDEN = 119; + +/** + * Error code indicating the result was not found in the cache. + * @property CACHE_MISS + * @static + * @final + */ +ParseError.CACHE_MISS = 120; + +/** + * Error code indicating that an invalid key was used in a nested + * JSONObject. + * @property INVALID_NESTED_KEY + * @static + * @final + */ +ParseError.INVALID_NESTED_KEY = 121; + +/** + * Error code indicating that an invalid filename was used for ParseFile. + * A valid file name contains only a-zA-Z0-9_. characters and is between 1 + * and 128 characters. + * @property INVALID_FILE_NAME + * @static + * @final + */ +ParseError.INVALID_FILE_NAME = 122; + +/** + * Error code indicating an invalid ACL was provided. + * @property INVALID_ACL + * @static + * @final + */ +ParseError.INVALID_ACL = 123; + +/** + * Error code indicating that the request timed out on the server. Typically + * this indicates that the request is too expensive to run. + * @property TIMEOUT + * @static + * @final + */ +ParseError.TIMEOUT = 124; + +/** + * Error code indicating that the email address was invalid. + * @property INVALID_EMAIL_ADDRESS + * @static + * @final + */ +ParseError.INVALID_EMAIL_ADDRESS = 125; + +/** + * Error code indicating a missing content type. + * @property MISSING_CONTENT_TYPE + * @static + * @final + */ +ParseError.MISSING_CONTENT_TYPE = 126; + +/** + * Error code indicating a missing content length. + * @property MISSING_CONTENT_LENGTH + * @static + * @final + */ +ParseError.MISSING_CONTENT_LENGTH = 127; + +/** + * Error code indicating an invalid content length. + * @property INVALID_CONTENT_LENGTH + * @static + * @final + */ +ParseError.INVALID_CONTENT_LENGTH = 128; + +/** + * Error code indicating a file that was too large. + * @property FILE_TOO_LARGE + * @static + * @final + */ +ParseError.FILE_TOO_LARGE = 129; + +/** + * Error code indicating an error saving a file. + * @property FILE_SAVE_ERROR + * @static + * @final + */ +ParseError.FILE_SAVE_ERROR = 130; + +/** + * Error code indicating that a unique field was given a value that is + * already taken. + * @property DUPLICATE_VALUE + * @static + * @final + */ +ParseError.DUPLICATE_VALUE = 137; + +/** + * Error code indicating that a role's name is invalid. + * @property INVALID_ROLE_NAME + * @static + * @final + */ +ParseError.INVALID_ROLE_NAME = 139; + +/** + * Error code indicating that an application quota was exceeded. Upgrade to + * resolve. + * @property EXCEEDED_QUOTA + * @static + * @final + */ +ParseError.EXCEEDED_QUOTA = 140; + +/** + * Error code indicating that a Cloud Code script failed. + * @property SCRIPT_FAILED + * @static + * @final + */ +ParseError.SCRIPT_FAILED = 141; + +/** + * Error code indicating that a Cloud Code validation failed. + * @property VALIDATION_ERROR + * @static + * @final + */ +ParseError.VALIDATION_ERROR = 142; + +/** + * Error code indicating that invalid image data was provided. + * @property INVALID_IMAGE_DATA + * @static + * @final + */ +ParseError.INVALID_IMAGE_DATA = 143; + +/** + * Error code indicating an unsaved file. + * @property UNSAVED_FILE_ERROR + * @static + * @final + */ +ParseError.UNSAVED_FILE_ERROR = 151; + +/** + * Error code indicating an invalid push time. + * @property INVALID_PUSH_TIME_ERROR + * @static + * @final + */ +ParseError.INVALID_PUSH_TIME_ERROR = 152; + +/** + * Error code indicating an error deleting a file. + * @property FILE_DELETE_ERROR + * @static + * @final + */ +ParseError.FILE_DELETE_ERROR = 153; + +/** + * Error code indicating that the application has exceeded its request + * limit. + * @property REQUEST_LIMIT_EXCEEDED + * @static + * @final + */ +ParseError.REQUEST_LIMIT_EXCEEDED = 155; + +/** + * Error code indicating an invalid event name. + * @property INVALID_EVENT_NAME + * @static + * @final + */ +ParseError.INVALID_EVENT_NAME = 160; + +/** + * Error code indicating that the username is missing or empty. + * @property USERNAME_MISSING + * @static + * @final + */ +ParseError.USERNAME_MISSING = 200; + +/** + * Error code indicating that the password is missing or empty. + * @property PASSWORD_MISSING + * @static + * @final + */ +ParseError.PASSWORD_MISSING = 201; + +/** + * Error code indicating that the username has already been taken. + * @property USERNAME_TAKEN + * @static + * @final + */ +ParseError.USERNAME_TAKEN = 202; + +/** + * Error code indicating that the email has already been taken. + * @property EMAIL_TAKEN + * @static + * @final + */ +ParseError.EMAIL_TAKEN = 203; + +/** + * Error code indicating that the email is missing, but must be specified. + * @property EMAIL_MISSING + * @static + * @final + */ +ParseError.EMAIL_MISSING = 204; + +/** + * Error code indicating that a user with the specified email was not found. + * @property EMAIL_NOT_FOUND + * @static + * @final + */ +ParseError.EMAIL_NOT_FOUND = 205; + +/** + * Error code indicating that a user object without a valid session could + * not be altered. + * @property SESSION_MISSING + * @static + * @final + */ +ParseError.SESSION_MISSING = 206; + +/** + * Error code indicating that a user can only be created through signup. + * @property MUST_CREATE_USER_THROUGH_SIGNUP + * @static + * @final + */ +ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; + +/** + * Error code indicating that an an account being linked is already linked + * to another user. + * @property ACCOUNT_ALREADY_LINKED + * @static + * @final + */ +ParseError.ACCOUNT_ALREADY_LINKED = 208; + +/** + * Error code indicating that the current session token is invalid. + * @property INVALID_SESSION_TOKEN + * @static + * @final + */ +ParseError.INVALID_SESSION_TOKEN = 209; + +/** + * Error code indicating that a user cannot be linked to an account because + * that account's id could not be found. + * @property LINKED_ID_MISSING + * @static + * @final + */ +ParseError.LINKED_ID_MISSING = 250; + +/** + * Error code indicating that a user with a linked (e.g. Facebook) account + * has an invalid session. + * @property INVALID_LINKED_SESSION + * @static + * @final + */ +ParseError.INVALID_LINKED_SESSION = 251; + +/** + * Error code indicating that a service being linked (e.g. Facebook or + * Twitter) is unsupported. + * @property UNSUPPORTED_SERVICE + * @static + * @final + */ +ParseError.UNSUPPORTED_SERVICE = 252; + +/** + * Error code indicating that there were multiple errors. Aggregate errors + * have an "errors" property, which is an array of error objects with more + * detail about each error that occurred. + * @property AGGREGATE_ERROR + * @static + * @final + */ +ParseError.AGGREGATE_ERROR = 600; + +/** + * Error code indicating the client was unable to read an input file. + * @property FILE_READ_ERROR + * @static + * @final + */ +ParseError.FILE_READ_ERROR = 601; + +/** + * Error code indicating a real error code is unavailable because + * we had to use an XDomainRequest object to allow CORS requests in + * Internet Explorer, which strips the body from HTTP responses that have + * a non-2XX status code. + * @property X_DOMAIN_REQUEST + * @static + * @final + */ +ParseError.X_DOMAIN_REQUEST = 602; +},{"babel-runtime/helpers/classCallCheck":56}],14:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; + +function b64Digit(number) { + if (number < 26) { + return String.fromCharCode(65 + number); + } + if (number < 52) { + return String.fromCharCode(97 + (number - 26)); + } + if (number < 62) { + return String.fromCharCode(48 + (number - 52)); + } + if (number === 62) { + return '+'; + } + if (number === 63) { + return '/'; + } + throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); +} + +/** + * A Parse.File is a local representation of a file that is saved to the Parse + * cloud. + * @class Parse.File + * @constructor + * @param name {String} The file's name. This will be prefixed by a unique + * value once the file has finished saving. The file name must begin with + * an alphanumeric character, and consist of alphanumeric characters, + * periods, spaces, underscores, or dashes. + * @param data {Array} The data for the file, as either: + * 1. an Array of byte value Numbers, or + * 2. an Object like { base64: "..." } with a base64-encoded String. + * 3. a File object selected with a file upload control. (3) only works + * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. + * For example:
+ * var fileUploadControl = $("#profilePhotoFileUpload")[0];
+ * if (fileUploadControl.files.length > 0) {
+ *   var file = fileUploadControl.files[0];
+ *   var name = "photo.jpg";
+ *   var parseFile = new Parse.File(name, file);
+ *   parseFile.save().then(function() {
+ *     // The file has been saved to Parse.
+ *   }, function(error) {
+ *     // The file either could not be read, or could not be saved to Parse.
+ *   });
+ * }
+ * @param type {String} Optional Content-Type header to use for the file. If + * this is omitted, the content type will be inferred from the name's + * extension. + */ + +var ParseFile = function () { + function ParseFile(name, data, type) { + (0, _classCallCheck3.default)(this, ParseFile); + + var specifiedType = type || ''; + + this._name = name; + + if (data !== undefined) { + if (Array.isArray(data)) { + this._source = { + format: 'base64', + base64: ParseFile.encodeBase64(data), + type: specifiedType + }; + } else if (typeof File !== 'undefined' && data instanceof File) { + this._source = { + format: 'file', + file: data, + type: specifiedType + }; + } else if (data && typeof data.base64 === 'string') { + var _base = data.base64; + var commaIndex = _base.indexOf(','); + + if (commaIndex !== -1) { + var matches = dataUriRegexp.exec(_base.slice(0, commaIndex + 1)); + // if data URI with type and charset, there will be 4 matches. + this._source = { + format: 'base64', + base64: _base.slice(commaIndex + 1), + type: matches[1] + }; + } else { + this._source = { + format: 'base64', + base64: _base, + type: specifiedType + }; + } + } else { + throw new TypeError('Cannot create a Parse.File with that data.'); + } + } + } + + /** + * Gets the name of the file. Before save is called, this is the filename + * given by the user. After save is called, that name gets prefixed with a + * unique identifier. + * @method name + * @return {String} + */ + + (0, _createClass3.default)(ParseFile, [{ + key: 'name', + value: function () { + return this._name; + } + + /** + * Gets the url of the file. It is only available after you save the file or + * after you get the file from a Parse.Object. + * @method url + * @param {Object} options An object to specify url options + * @return {String} + */ + + }, { + key: 'url', + value: function (options) { + options = options || {}; + if (!this._url) { + return; + } + if (options.forceSecure) { + return this._url.replace(/^http:\/\//i, 'https://'); + } else { + return this._url; + } + } + + /** + * Saves the file to the Parse cloud. + * @method save + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} Promise that is resolved when the save finishes. + */ + + }, { + key: 'save', + value: function (options) { + var _this = this; + + options = options || {}; + var controller = _CoreManager2.default.getFileController(); + if (!this._previousSave) { + if (this._source.format === 'file') { + this._previousSave = controller.saveFile(this._name, this._source).then(function (res) { + _this._name = res.name; + _this._url = res.url; + return _this; + }); + } else { + this._previousSave = controller.saveBase64(this._name, this._source).then(function (res) { + _this._name = res.name; + _this._url = res.url; + return _this; + }); + } + } + if (this._previousSave) { + return this._previousSave._thenRunCallbacks(options); + } + } + }, { + key: 'toJSON', + value: function () { + return { + __type: 'File', + name: this._name, + url: this._url + }; + } + }, { + key: 'equals', + value: function (other) { + if (this === other) { + return true; + } + // Unsaved Files are never equal, since they will be saved to different URLs + return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; + } + }], [{ + key: 'fromJSON', + value: function (obj) { + if (obj.__type !== 'File') { + throw new TypeError('JSON object does not represent a ParseFile'); + } + var file = new ParseFile(obj.name); + file._url = obj.url; + return file; + } + }, { + key: 'encodeBase64', + value: function (bytes) { + var chunks = []; + chunks.length = Math.ceil(bytes.length / 3); + for (var i = 0; i < chunks.length; i++) { + var b1 = bytes[i * 3]; + var b2 = bytes[i * 3 + 1] || 0; + var b3 = bytes[i * 3 + 2] || 0; + + var has2 = i * 3 + 1 < bytes.length; + var has3 = i * 3 + 2 < bytes.length; + + chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); + } + + return chunks.join(''); + } + }]); + return ParseFile; +}(); + +exports.default = ParseFile; + +var DefaultController = { + saveFile: function (name, source) { + if (source.format !== 'file') { + throw new Error('saveFile can only be used with File-type sources.'); + } + // To directly upload a File, we use a REST-style AJAX request + var headers = { + 'X-Parse-Application-ID': _CoreManager2.default.get('APPLICATION_ID'), + 'X-Parse-JavaScript-Key': _CoreManager2.default.get('JAVASCRIPT_KEY'), + 'Content-Type': source.type || (source.file ? source.file.type : null) + }; + var url = _CoreManager2.default.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += 'files/' + name; + return _CoreManager2.default.getRESTController().ajax('POST', url, source.file, headers); + }, + + saveBase64: function (name, source) { + if (source.format !== 'base64') { + throw new Error('saveBase64 can only be used with Base64-type sources.'); + } + var data = { + base64: source.base64 + }; + if (source.type) { + data._ContentType = source.type; + } + + return _CoreManager2.default.getRESTController().request('POST', 'files/' + name, data); + } +}; + +_CoreManager2.default.setFileController(DefaultController); +},{"./CoreManager":3,"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],15:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new GeoPoint with any of the following forms:
+ *
+ *   new GeoPoint(otherGeoPoint)
+ *   new GeoPoint(30, 30)
+ *   new GeoPoint([30, 30])
+ *   new GeoPoint({latitude: 30, longitude: 30})
+ *   new GeoPoint()  // defaults to (0, 0)
+ *   
+ * @class Parse.GeoPoint + * @constructor + * + *

Represents a latitude / longitude point that may be associated + * with a key in a ParseObject or used as a reference point for geo queries. + * This allows proximity-based queries on the key.

+ * + *

Only one key in a class may contain a GeoPoint.

+ * + *

Example:

+ *   var point = new Parse.GeoPoint(30.0, -20.0);
+ *   var object = new Parse.Object("PlaceObject");
+ *   object.set("location", point);
+ *   object.save();

+ */ +var ParseGeoPoint = function () { + function ParseGeoPoint(arg1, arg2) { + (0, _classCallCheck3.default)(this, ParseGeoPoint); + + if (Array.isArray(arg1)) { + ParseGeoPoint._validate(arg1[0], arg1[1]); + this._latitude = arg1[0]; + this._longitude = arg1[1]; + } else if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { + ParseGeoPoint._validate(arg1.latitude, arg1.longitude); + this._latitude = arg1.latitude; + this._longitude = arg1.longitude; + } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { + ParseGeoPoint._validate(arg1, arg2); + this._latitude = arg1; + this._longitude = arg2; + } else { + this._latitude = 0; + this._longitude = 0; + } + } + + /** + * North-south portion of the coordinate, in range [-90, 90]. + * Throws an exception if set out of range in a modern browser. + * @property latitude + * @type Number + */ + + (0, _createClass3.default)(ParseGeoPoint, [{ + key: 'toJSON', + + /** + * Returns a JSON representation of the GeoPoint, suitable for Parse. + * @method toJSON + * @return {Object} + */ + value: function () { + ParseGeoPoint._validate(this._latitude, this._longitude); + return { + __type: 'GeoPoint', + latitude: this._latitude, + longitude: this._longitude + }; + } + }, { + key: 'equals', + value: function (other) { + return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; + } + + /** + * Returns the distance from this GeoPoint to another in radians. + * @method radiansTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'radiansTo', + value: function (point) { + var d2r = Math.PI / 180.0; + var lat1rad = this.latitude * d2r; + var long1rad = this.longitude * d2r; + var lat2rad = point.latitude * d2r; + var long2rad = point.longitude * d2r; + + var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); + var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); + // Square of half the straight line chord distance between both points. + var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; + a = Math.min(1.0, a); + return 2 * Math.asin(Math.sqrt(a)); + } + + /** + * Returns the distance from this GeoPoint to another in kilometers. + * @method kilometersTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'kilometersTo', + value: function (point) { + return this.radiansTo(point) * 6371.0; + } + + /** + * Returns the distance from this GeoPoint to another in miles. + * @method milesTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'milesTo', + value: function (point) { + return this.radiansTo(point) * 3958.8; + } + + /** + * Throws an exception if the given lat-long is out of bounds. + */ + + }, { + key: 'latitude', + get: function () { + return this._latitude; + }, + set: function (val) { + ParseGeoPoint._validate(val, this.longitude); + this._latitude = val; + } + + /** + * East-west portion of the coordinate, in range [-180, 180]. + * Throws if set out of range in a modern browser. + * @property longitude + * @type Number + */ + + }, { + key: 'longitude', + get: function () { + return this._longitude; + }, + set: function (val) { + ParseGeoPoint._validate(this.latitude, val); + this._longitude = val; + } + }], [{ + key: '_validate', + value: function (latitude, longitude) { + if (latitude !== latitude || longitude !== longitude) { + throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); + } + if (latitude < -90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); + } + if (latitude > 90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); + } + if (longitude < -180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); + } + if (longitude > 180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); + } + } + + /** + * Creates a GeoPoint with the user's current location, if available. + * Calls options.success with a new GeoPoint instance or calls options.error. + * @method current + * @param {Object} options An object with success and error callbacks. + * @static + */ + + }, { + key: 'current', + value: function (options) { + var promise = new _ParsePromise2.default(); + navigator.geolocation.getCurrentPosition(function (location) { + promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); + }, function (error) { + promise.reject(error); + }); + + return promise._thenRunCallbacks(options); + } + }]); + return ParseGeoPoint; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseGeoPoint; +},{"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],16:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _ParseObject2 = _dereq_('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var Installation = function (_ParseObject) { + (0, _inherits3.default)(Installation, _ParseObject); + + function Installation(attributes) { + (0, _classCallCheck3.default)(this, Installation); + + var _this = (0, _possibleConstructorReturn3.default)(this, (Installation.__proto__ || (0, _getPrototypeOf2.default)(Installation)).call(this, '_Installation')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + return _this; + } + + return Installation; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = Installation; + +_ParseObject3.default.registerSubclass('_Installation', Installation); +},{"./ParseObject":18,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],17:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _EventEmitter = _dereq_('./EventEmitter'); + +var _EventEmitter2 = _interopRequireDefault(_EventEmitter); + +var _LiveQueryClient = _dereq_('./LiveQueryClient'); + +var _LiveQueryClient2 = _interopRequireDefault(_LiveQueryClient); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function open() { + var LiveQueryController = _CoreManager2.default.getLiveQueryController(); + LiveQueryController.open(); +} + +function close() { + var LiveQueryController = _CoreManager2.default.getLiveQueryController(); + LiveQueryController.close(); +} + +/** + * + * We expose three events to help you monitor the status of the WebSocket connection: + * + *

Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

+ * Parse.LiveQuery.on('open', () => {
+ * 
+ * });

+ * + *

Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

+ * Parse.LiveQuery.on('close', () => {
+ * 
+ * });

+ * + *

Error - When some network error or LiveQuery server error happens, you'll get this event. + * + *

+ * Parse.LiveQuery.on('error', (error) => {
+ * 
+ * });

+ * + * @class Parse.LiveQuery + * @static + * + */ +var LiveQuery = new _EventEmitter2.default(); + +/** + * After open is called, the LiveQuery will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ +LiveQuery.open = open; + +/** + * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). + * This function will close the WebSocket connection to the LiveQuery server, + * cancel the auto reconnect, and unsubscribe all subscriptions based on it. + * If you call query.subscribe() after this, we'll create a new WebSocket + * connection to the LiveQuery server. + * + * @method close + */ + +LiveQuery.close = close; +// Register a default onError callback to make sure we do not crash on error +LiveQuery.on('error', function () {}); + +exports.default = LiveQuery; + +function getSessionToken() { + var controller = _CoreManager2.default.getUserController(); + return controller.currentUserAsync().then(function (currentUser) { + return currentUser ? currentUser.getSessionToken() : undefined; + }); +} + +function getLiveQueryClient() { + return _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient(); +} + +var defaultLiveQueryClient = void 0; +var DefaultLiveQueryController = { + setDefaultLiveQueryClient: function (liveQueryClient) { + defaultLiveQueryClient = liveQueryClient; + }, + getDefaultLiveQueryClient: function () { + if (defaultLiveQueryClient) { + return _ParsePromise2.default.as(defaultLiveQueryClient); + } + + return getSessionToken().then(function (sessionToken) { + var liveQueryServerURL = _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); + + if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL + if (!liveQueryServerURL) { + var tempServerURL = _CoreManager2.default.get('SERVER_URL'); + var protocol = 'ws://'; + // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix + if (tempServerURL.indexOf('https') === 0) { + protocol = 'wss://'; + } + var host = tempServerURL.replace(/^https?:\/\//, ''); + liveQueryServerURL = protocol + host; + _CoreManager2.default.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); + } + + var applicationId = _CoreManager2.default.get('APPLICATION_ID'); + var javascriptKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); + var masterKey = _CoreManager2.default.get('MASTER_KEY'); + // Get currentUser sessionToken if possible + defaultLiveQueryClient = new _LiveQueryClient2.default({ + applicationId: applicationId, + serverURL: liveQueryServerURL, + javascriptKey: javascriptKey, + masterKey: masterKey, + sessionToken: sessionToken + }); + // Register a default onError callback to make sure we do not crash on error + // Cannot create these events on a nested way because of EventEmiiter from React Native + defaultLiveQueryClient.on('error', function (error) { + LiveQuery.emit('error', error); + }); + defaultLiveQueryClient.on('open', function () { + LiveQuery.emit('open'); + }); + defaultLiveQueryClient.on('close', function () { + LiveQuery.emit('close'); + }); + + return defaultLiveQueryClient; + }); + }, + open: function () { + var _this = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this.resolve(liveQueryClient.open()); + }); + }, + close: function () { + var _this2 = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this2.resolve(liveQueryClient.close()); + }); + }, + subscribe: function (query) { + var _this3 = this; + + var subscriptionWrap = new _EventEmitter2.default(); + + getLiveQueryClient().then(function (liveQueryClient) { + if (liveQueryClient.shouldOpen()) { + liveQueryClient.open(); + } + var promiseSessionToken = getSessionToken(); + // new event emitter + return promiseSessionToken.then(function (sessionToken) { + + var subscription = liveQueryClient.subscribe(query, sessionToken); + // enter, leave create, etc + + subscriptionWrap.id = subscription.id; + subscriptionWrap.query = subscription.query; + subscriptionWrap.sessionToken = subscription.sessionToken; + subscriptionWrap.unsubscribe = subscription.unsubscribe; + // Cannot create these events on a nested way because of EventEmiiter from React Native + subscription.on('open', function () { + subscriptionWrap.emit('open'); + }); + subscription.on('create', function (object) { + subscriptionWrap.emit('create', object); + }); + subscription.on('update', function (object) { + subscriptionWrap.emit('update', object); + }); + subscription.on('enter', function (object) { + subscriptionWrap.emit('enter', object); + }); + subscription.on('leave', function (object) { + subscriptionWrap.emit('leave', object); + }); + subscription.on('delete', function (object) { + subscriptionWrap.emit('delete', object); + }); + + _this3.resolve(); + }); + }); + return subscriptionWrap; + }, + unsubscribe: function (subscription) { + var _this4 = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this4.resolve(liveQueryClient.unsubscribe(subscription)); + }); + }, + _clearCachedDefaultClient: function () { + defaultLiveQueryClient = null; + } +}; + +_CoreManager2.default.setLiveQueryController(DefaultLiveQueryController); +},{"./CoreManager":3,"./EventEmitter":4,"./LiveQueryClient":7,"./ParsePromise":20}],18:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _defineProperty = _dereq_('babel-runtime/core-js/object/define-property'); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +var _create = _dereq_('babel-runtime/core-js/object/create'); + +var _create2 = _interopRequireDefault(_create); + +var _freeze = _dereq_('babel-runtime/core-js/object/freeze'); + +var _freeze2 = _interopRequireDefault(_freeze); + +var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _keys = _dereq_('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _canBeSerialized = _dereq_('./canBeSerialized'); + +var _canBeSerialized2 = _interopRequireDefault(_canBeSerialized); + +var _decode = _dereq_('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _equals = _dereq_('./equals'); + +var _equals2 = _interopRequireDefault(_equals); + +var _escape2 = _dereq_('./escape'); + +var _escape3 = _interopRequireDefault(_escape2); + +var _ParseACL = _dereq_('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _parseDate = _dereq_('./parseDate'); + +var _parseDate2 = _interopRequireDefault(_parseDate); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseOp = _dereq_('./ParseOp'); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseQuery = _dereq_('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _SingleInstanceStateController = _dereq_('./SingleInstanceStateController'); + +var SingleInstanceStateController = _interopRequireWildcard(_SingleInstanceStateController); + +var _unique = _dereq_('./unique'); + +var _unique2 = _interopRequireDefault(_unique); + +var _UniqueInstanceStateController = _dereq_('./UniqueInstanceStateController'); + +var UniqueInstanceStateController = _interopRequireWildcard(_UniqueInstanceStateController); + +var _unsavedChildren = _dereq_('./unsavedChildren'); + +var _unsavedChildren2 = _interopRequireDefault(_unsavedChildren); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +// Mapping of class names to constructors, so we can populate objects from the +// server with appropriate subclasses of ParseObject +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var classMap = {}; + +// Global counter for generating unique local Ids +var localCount = 0; +// Global counter for generating unique Ids for non-single-instance objects +var objectCount = 0; +// On web clients, objects are single-instance: any two objects with the same Id +// will have the same attributes. However, this may be dangerous default +// behavior in a server scenario +var singleInstance = !_CoreManager2.default.get('IS_NODE'); +if (singleInstance) { + _CoreManager2.default.setObjectStateController(SingleInstanceStateController); +} else { + _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); +} + +function getServerUrlPath() { + var serverUrl = _CoreManager2.default.get('SERVER_URL'); + if (serverUrl[serverUrl.length - 1] !== '/') { + serverUrl += '/'; + } + var url = serverUrl.replace(/https?:\/\//, ''); + return url.substr(url.indexOf('/')); +} + +/** + * Creates a new model with defined attributes. + * + *

You won't normally call this method directly. It is recommended that + * you use a subclass of Parse.Object instead, created by calling + * extend.

+ * + *

However, if you don't want to use a subclass, or aren't sure which + * subclass is appropriate, you can use this form:

+ *     var object = new Parse.Object("ClassName");
+ * 
+ * That is basically equivalent to:
+ *     var MyClass = Parse.Object.extend("ClassName");
+ *     var object = new MyClass();
+ * 

+ * + * @class Parse.Object + * @constructor + * @param {String} className The class name for the object + * @param {Object} attributes The initial set of data to store in the object. + * @param {Object} options The options for this object instance. + */ + +var ParseObject = function () { + /** + * The ID of this object, unique within its class. + * @property id + * @type String + */ + function ParseObject(className, attributes, options) { + (0, _classCallCheck3.default)(this, ParseObject); + + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + var toSet = null; + this._objCount = objectCount++; + if (typeof className === 'string') { + this.className = className; + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + toSet = attributes; + } + } else if (className && (typeof className === 'undefined' ? 'undefined' : (0, _typeof3.default)(className)) === 'object') { + this.className = className.className; + toSet = {}; + for (var attr in className) { + if (attr !== 'className') { + toSet[attr] = className[attr]; + } + } + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + options = attributes; + } + } + if (toSet && !this.set(toSet, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + + /** Prototype getters / setters **/ + + (0, _createClass3.default)(ParseObject, [{ + key: '_getId', + + /** Private methods **/ + + /** + * Returns a local or server Id used uniquely identify this object + */ + value: function () { + if (typeof this.id === 'string') { + return this.id; + } + if (typeof this._localId === 'string') { + return this._localId; + } + var localId = 'local' + String(localCount++); + this._localId = localId; + return localId; + } + + /** + * Returns a unique identifier used to pull data from the State Controller. + */ + + }, { + key: '_getStateIdentifier', + value: function () { + if (singleInstance) { + var _id = this.id; + if (!_id) { + _id = this._getId(); + } + return { + id: _id, + className: this.className + }; + } else { + return this; + } + } + }, { + key: '_getServerData', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return stateController.getServerData(this._getStateIdentifier()); + } + }, { + key: '_clearServerData', + value: function () { + var serverData = this._getServerData(); + var unset = {}; + for (var attr in serverData) { + unset[attr] = undefined; + } + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.setServerData(this._getStateIdentifier(), unset); + } + }, { + key: '_getPendingOps', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return stateController.getPendingOps(this._getStateIdentifier()); + } + }, { + key: '_clearPendingOps', + value: function () { + var pending = this._getPendingOps(); + var latest = pending[pending.length - 1]; + var keys = (0, _keys2.default)(latest); + keys.forEach(function (key) { + delete latest[key]; + }); + } + }, { + key: '_getDirtyObjectAttributes', + value: function () { + var attributes = this.attributes; + var stateController = _CoreManager2.default.getObjectStateController(); + var objectCache = stateController.getObjectCache(this._getStateIdentifier()); + var dirty = {}; + for (var attr in attributes) { + var val = attributes[attr]; + if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof ParseObject) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { + // Due to the way browsers construct maps, the key order will not change + // unless the object is changed + try { + var json = (0, _encode2.default)(val, false, true); + var stringified = (0, _stringify2.default)(json); + if (objectCache[attr] !== stringified) { + dirty[attr] = val; + } + } catch (e) { + // Error occurred, possibly by a nested unsaved pointer in a mutable container + // No matter how it happened, it indicates a change in the attribute + dirty[attr] = val; + } + } + } + return dirty; + } + }, { + key: '_toFullJSON', + value: function (seen) { + var json = this.toJSON(seen); + json.__type = 'Object'; + json.className = this.className; + return json; + } + }, { + key: '_getSaveJSON', + value: function () { + var pending = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + var json = {}; + + for (var attr in dirtyObjects) { + json[attr] = new _ParseOp.SetOp(dirtyObjects[attr]).toJSON(); + } + for (attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + return json; + } + }, { + key: '_getSaveParams', + value: function () { + var method = this.id ? 'PUT' : 'POST'; + var body = this._getSaveJSON(); + var path = 'classes/' + this.className; + if (this.id) { + path += '/' + this.id; + } else if (this.className === '_User') { + path = 'users'; + } + return { + method: method, + body: body, + path: path + }; + } + }, { + key: '_finishFetch', + value: function (serverData) { + if (!this.id && serverData.objectId) { + this.id = serverData.objectId; + } + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.initializeState(this._getStateIdentifier()); + var decoded = {}; + for (var attr in serverData) { + if (attr === 'ACL') { + decoded[attr] = new _ParseACL2.default(serverData[attr]); + } else if (attr !== 'objectId') { + decoded[attr] = (0, _decode2.default)(serverData[attr]); + if (decoded[attr] instanceof _ParseRelation2.default) { + decoded[attr]._ensureParentAndKey(this, attr); + } + } + } + if (decoded.createdAt && typeof decoded.createdAt === 'string') { + decoded.createdAt = (0, _parseDate2.default)(decoded.createdAt); + } + if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { + decoded.updatedAt = (0, _parseDate2.default)(decoded.updatedAt); + } + if (!decoded.updatedAt && decoded.createdAt) { + decoded.updatedAt = decoded.createdAt; + } + stateController.commitServerChanges(this._getStateIdentifier(), decoded); + } + }, { + key: '_setExisted', + value: function (existed) { + var stateController = _CoreManager2.default.getObjectStateController(); + var state = stateController.getState(this._getStateIdentifier()); + if (state) { + state.existed = existed; + } + } + }, { + key: '_migrateId', + value: function (serverId) { + if (this._localId && serverId) { + if (singleInstance) { + var stateController = _CoreManager2.default.getObjectStateController(); + var oldState = stateController.removeState(this._getStateIdentifier()); + this.id = serverId; + delete this._localId; + if (oldState) { + stateController.initializeState(this._getStateIdentifier(), oldState); + } + } else { + this.id = serverId; + delete this._localId; + } + } + } + }, { + key: '_handleSaveResponse', + value: function (response, status) { + var changes = {}; + + var stateController = _CoreManager2.default.getObjectStateController(); + var pending = stateController.popPendingState(this._getStateIdentifier()); + for (var attr in pending) { + if (pending[attr] instanceof _ParseOp.RelationOp) { + changes[attr] = pending[attr].applyTo(undefined, this, attr); + } else if (!(attr in response)) { + // Only SetOps and UnsetOps should not come back with results + changes[attr] = pending[attr].applyTo(undefined); + } + } + for (attr in response) { + if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { + changes[attr] = (0, _parseDate2.default)(response[attr]); + } else if (attr === 'ACL') { + changes[attr] = new _ParseACL2.default(response[attr]); + } else if (attr !== 'objectId') { + changes[attr] = (0, _decode2.default)(response[attr]); + if (changes[attr] instanceof _ParseOp.UnsetOp) { + changes[attr] = undefined; + } + } + } + if (changes.createdAt && !changes.updatedAt) { + changes.updatedAt = changes.createdAt; + } + + this._migrateId(response.objectId); + + if (status !== 201) { + this._setExisted(true); + } + + stateController.commitServerChanges(this._getStateIdentifier(), changes); + } + }, { + key: '_handleSaveError', + value: function () { + this._getPendingOps(); + + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.mergeFirstPendingState(this._getStateIdentifier()); + } + + /** Public methods **/ + + }, { + key: 'initialize', + value: function () {} + // NOOP + + + /** + * Returns a JSON version of the object suitable for saving to Parse. + * @method toJSON + * @return {Object} + */ + + }, { + key: 'toJSON', + value: function (seen) { + var seenEntry = this.id ? this.className + ':' + this.id : this; + var seen = seen || [seenEntry]; + var json = {}; + var attrs = this.attributes; + for (var attr in attrs) { + if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { + json[attr] = attrs[attr].toJSON(); + } else { + json[attr] = (0, _encode2.default)(attrs[attr], false, false, seen); + } + } + var pending = this._getPendingOps(); + for (var attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + + if (this.id) { + json.objectId = this.id; + } + return json; + } + + /** + * Determines whether this ParseObject is equal to another ParseObject + * @method equals + * @return {Boolean} + */ + + }, { + key: 'equals', + value: function (other) { + if (this === other) { + return true; + } + return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; + } + + /** + * Returns true if this object has been modified since its last + * save/refresh. If an attribute is specified, it returns true only if that + * particular attribute has been modified since the last save/refresh. + * @method dirty + * @param {String} attr An attribute name (optional). + * @return {Boolean} + */ + + }, { + key: 'dirty', + value: function (attr) { + if (!this.id) { + return true; + } + var pendingOps = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + if (attr) { + if (dirtyObjects.hasOwnProperty(attr)) { + return true; + } + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i].hasOwnProperty(attr)) { + return true; + } + } + return false; + } + if ((0, _keys2.default)(pendingOps[0]).length !== 0) { + return true; + } + if ((0, _keys2.default)(dirtyObjects).length !== 0) { + return true; + } + return false; + } + + /** + * Returns an array of keys that have been modified since last save/refresh + * @method dirtyKeys + * @return {Array of string} + */ + + }, { + key: 'dirtyKeys', + value: function () { + var pendingOps = this._getPendingOps(); + var keys = {}; + for (var i = 0; i < pendingOps.length; i++) { + for (var attr in pendingOps[i]) { + keys[attr] = true; + } + } + var dirtyObjects = this._getDirtyObjectAttributes(); + for (var attr in dirtyObjects) { + keys[attr] = true; + } + return (0, _keys2.default)(keys); + } + + /** + * Gets a Pointer referencing this Object. + * @method toPointer + * @return {Object} + */ + + }, { + key: 'toPointer', + value: function () { + if (!this.id) { + throw new Error('Cannot create a pointer to an unsaved ParseObject'); + } + return { + __type: 'Pointer', + className: this.className, + objectId: this.id + }; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'get', + value: function (attr) { + return this.attributes[attr]; + } + + /** + * Gets a relation on the given class for the attribute. + * @method relation + * @param String attr The attribute to get the relation for. + */ + + }, { + key: 'relation', + value: function (attr) { + var value = this.get(attr); + if (value) { + if (!(value instanceof _ParseRelation2.default)) { + throw new Error('Called relation() on non-relation field ' + attr); + } + value._ensureParentAndKey(this, attr); + return value; + } + return new _ParseRelation2.default(this, attr); + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'escape', + value: function (attr) { + var val = this.attributes[attr]; + if (val == null) { + return ''; + } + + if (typeof val !== 'string') { + if (typeof val.toString !== 'function') { + return ''; + } + val = val.toString(); + } + return (0, _escape3.default)(val); + } + + /** + * Returns true if the attribute contains a value that is not + * null or undefined. + * @method has + * @param {String} attr The string name of the attribute. + * @return {Boolean} + */ + + }, { + key: 'has', + value: function (attr) { + var attributes = this.attributes; + if (attributes.hasOwnProperty(attr)) { + return attributes[attr] != null; + } + return false; + } + + /** + * Sets a hash of model attributes on the object. + * + *

You can call it with an object containing keys and values, or with one + * key and value. For example:

+     *   gameTurn.set({
+     *     player: player1,
+     *     diceRoll: 2
+     *   }, {
+     *     error: function(gameTurnAgain, error) {
+     *       // The set failed validation.
+     *     }
+     *   });
+     *
+     *   game.set("currentPlayer", player2, {
+     *     error: function(gameTurnAgain, error) {
+     *       // The set failed validation.
+     *     }
+     *   });
+     *
+     *   game.set("finished", true);

+ * + * @method set + * @param {String} key The key to set. + * @param {} value The value to give it. + * @param {Object} options A set of options for the set. + * The only supported option is error. + * @return {Boolean} true if the set succeeded. + */ + + }, { + key: 'set', + value: function (key, value, options) { + var changes = {}; + var newOps = {}; + if (key && (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'object') { + changes = key; + options = value; + } else if (typeof key === 'string') { + changes[key] = value; + } else { + return this; + } + + options = options || {}; + var readonly = []; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var k in changes) { + if (k === 'createdAt' || k === 'updatedAt') { + // This property is read-only, but for legacy reasons we silently + // ignore it + continue; + } + if (readonly.indexOf(k) > -1) { + throw new Error('Cannot modify readonly attribute: ' + k); + } + if (options.unset) { + newOps[k] = new _ParseOp.UnsetOp(); + } else if (changes[k] instanceof _ParseOp.Op) { + newOps[k] = changes[k]; + } else if (changes[k] && (0, _typeof3.default)(changes[k]) === 'object' && typeof changes[k].__op === 'string') { + newOps[k] = (0, _ParseOp.opFromJSON)(changes[k]); + } else if (k === 'objectId' || k === 'id') { + if (typeof changes[k] === 'string') { + this.id = changes[k]; + } + } else if (k === 'ACL' && (0, _typeof3.default)(changes[k]) === 'object' && !(changes[k] instanceof _ParseACL2.default)) { + newOps[k] = new _ParseOp.SetOp(new _ParseACL2.default(changes[k])); + } else { + newOps[k] = new _ParseOp.SetOp(changes[k]); + } + } + + // Calculate new values + var currentAttributes = this.attributes; + var newValues = {}; + for (var attr in newOps) { + if (newOps[attr] instanceof _ParseOp.RelationOp) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); + } else if (!(newOps[attr] instanceof _ParseOp.UnsetOp)) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); + } + } + + // Validate changes + if (!options.ignoreValidation) { + var validation = this.validate(newValues); + if (validation) { + if (typeof options.error === 'function') { + options.error(this, validation); + } + return false; + } + } + + // Consolidate Ops + var pendingOps = this._getPendingOps(); + var last = pendingOps.length - 1; + var stateController = _CoreManager2.default.getObjectStateController(); + for (var attr in newOps) { + var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); + stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); + } + + return this; + } + + /** + * Remove an attribute from the model. This is a noop if the attribute doesn't + * exist. + * @method unset + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'unset', + value: function (attr, options) { + options = options || {}; + options.unset = true; + return this.set(attr, null, options); + } + + /** + * Atomically increments the value of the given attribute the next time the + * object is saved. If no amount is specified, 1 is used by default. + * + * @method increment + * @param attr {String} The key. + * @param amount {Number} The amount to increment by (optional). + */ + + }, { + key: 'increment', + value: function (attr, amount) { + if (typeof amount === 'undefined') { + amount = 1; + } + if (typeof amount !== 'number') { + throw new Error('Cannot increment by a non-numeric amount.'); + } + return this.set(attr, new _ParseOp.IncrementOp(amount)); + } + + /** + * Atomically add an object to the end of the array associated with a given + * key. + * @method add + * @param attr {String} The key. + * @param item {} The item to add. + */ + + }, { + key: 'add', + value: function (attr, item) { + return this.set(attr, new _ParseOp.AddOp([item])); + } + + /** + * Atomically add an object to the array associated with a given key, only + * if it is not already present in the array. The position of the insert is + * not guaranteed. + * + * @method addUnique + * @param attr {String} The key. + * @param item {} The object to add. + */ + + }, { + key: 'addUnique', + value: function (attr, item) { + return this.set(attr, new _ParseOp.AddUniqueOp([item])); + } + + /** + * Atomically remove all instances of an object from the array associated + * with a given key. + * + * @method remove + * @param attr {String} The key. + * @param item {} The object to remove. + */ + + }, { + key: 'remove', + value: function (attr, item) { + return this.set(attr, new _ParseOp.RemoveOp([item])); + } + + /** + * Returns an instance of a subclass of Parse.Op describing what kind of + * modification has been performed on this field since the last time it was + * saved. For example, after calling object.increment("x"), calling + * object.op("x") would return an instance of Parse.Op.Increment. + * + * @method op + * @param attr {String} The key. + * @returns {Parse.Op} The operation, or undefined if none. + */ + + }, { + key: 'op', + value: function (attr) { + var pending = this._getPendingOps(); + for (var i = pending.length; i--;) { + if (pending[i][attr]) { + return pending[i][attr]; + } + } + } + + /** + * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() + * @method clone + * @return {Parse.Object} + */ + + }, { + key: 'clone', + value: function () { + var clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + var attributes = this.attributes; + if (typeof this.constructor.readOnlyAttributes === 'function') { + var readonly = this.constructor.readOnlyAttributes() || []; + // Attributes are frozen, so we have to rebuild an object, + // rather than delete readonly keys + var copy = {}; + for (var a in attributes) { + if (readonly.indexOf(a) < 0) { + copy[a] = attributes[a]; + } + } + attributes = copy; + } + if (clone.set) { + clone.set(attributes); + } + return clone; + } + + /** + * Creates a new instance of this object. Not to be confused with clone() + * @method newInstance + * @return {Parse.Object} + */ + + }, { + key: 'newInstance', + value: function () { + var clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + clone.id = this.id; + if (singleInstance) { + // Just return an object with the right id + return clone; + } + + var stateController = _CoreManager2.default.getObjectStateController(); + if (stateController) { + stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); + } + return clone; + } + + /** + * Returns true if this object has never been saved to Parse. + * @method isNew + * @return {Boolean} + */ + + }, { + key: 'isNew', + value: function () { + return !this.id; + } + + /** + * Returns true if this object was created by the Parse server when the + * object might have already been there (e.g. in the case of a Facebook + * login) + * @method existed + * @return {Boolean} + */ + + }, { + key: 'existed', + value: function () { + if (!this.id) { + return false; + } + var stateController = _CoreManager2.default.getObjectStateController(); + var state = stateController.getState(this._getStateIdentifier()); + if (state) { + return state.existed; + } + return false; + } + + /** + * Checks if the model is currently in a valid state. + * @method isValid + * @return {Boolean} + */ + + }, { + key: 'isValid', + value: function () { + return !this.validate(this.attributes); + } + + /** + * You should not call this function directly unless you subclass + * Parse.Object, in which case you can override this method + * to provide additional validation on set and + * save. Your implementation should return + * + * @method validate + * @param {Object} attrs The current data to validate. + * @return {} False if the data is valid. An error object otherwise. + * @see Parse.Object#set + */ + + }, { + key: 'validate', + value: function (attrs) { + if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof _ParseACL2.default)) { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'ACL must be a Parse ACL.'); + } + for (var key in attrs) { + if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { + return new _ParseError2.default(_ParseError2.default.INVALID_KEY_NAME); + } + } + return false; + } + + /** + * Returns the ACL for this object. + * @method getACL + * @returns {Parse.ACL} An instance of Parse.ACL. + * @see Parse.Object#get + */ + + }, { + key: 'getACL', + value: function () { + var acl = this.get('ACL'); + if (acl instanceof _ParseACL2.default) { + return acl; + } + return null; + } + + /** + * Sets the ACL to be used for this object. + * @method setACL + * @param {Parse.ACL} acl An instance of Parse.ACL. + * @param {Object} options Optional Backbone-like options object to be + * passed in to set. + * @return {Boolean} Whether the set passed validation. + * @see Parse.Object#set + */ + + }, { + key: 'setACL', + value: function (acl, options) { + return this.set('ACL', acl, options); + } + + /** + * Clears any changes to this object made since the last call to save() + * @method revert + */ + + }, { + key: 'revert', + value: function () { + this._clearPendingOps(); + } + + /** + * Clears all attributes on a model + * @method clear + */ + + }, { + key: 'clear', + value: function () { + var attributes = this.attributes; + var erasable = {}; + var readonly = ['createdAt', 'updatedAt']; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var attr in attributes) { + if (readonly.indexOf(attr) < 0) { + erasable[attr] = true; + } + } + return this.set(erasable, { unset: true }); + } + + /** + * Fetch the model from the server. If the server's representation of the + * model differs from its current attributes, they will be overriden. + * + * @method fetch + * @param {Object} options A Backbone-style callback object. + * Valid options are:
    + *
  • success: A Backbone-style success callback. + *
  • error: An Backbone-style error callback. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * @return {Parse.Promise} A promise that is fulfilled when the fetch + * completes. + */ + + }, { + key: 'fetch', + value: function (options) { + options = options || {}; + var fetchOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + fetchOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + fetchOptions.sessionToken = options.sessionToken; + } + var controller = _CoreManager2.default.getObjectController(); + return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); + } + + /** + * Set a hash of model attributes, and save the model to the server. + * updatedAt will be updated when the request returns. + * You can either call it as:
+     *   object.save();
+ * or
+     *   object.save(null, options);
+ * or
+     *   object.save(attrs, options);
+ * or
+     *   object.save(key, value, options);
+ * + * For example,
+     *   gameTurn.save({
+     *     player: "Jake Cutter",
+     *     diceRoll: 2
+     *   }, {
+     *     success: function(gameTurnAgain) {
+     *       // The save was successful.
+     *     },
+     *     error: function(gameTurnAgain, error) {
+     *       // The save failed.  Error is an instance of Parse.Error.
+     *     }
+     *   });
+ * or with promises:
+     *   gameTurn.save({
+     *     player: "Jake Cutter",
+     *     diceRoll: 2
+     *   }).then(function(gameTurnAgain) {
+     *     // The save was successful.
+     *   }, function(error) {
+     *     // The save failed.  Error is an instance of Parse.Error.
+     *   });
+ * + * @method save + * @param {Object} options A Backbone-style callback object. + * Valid options are:
    + *
  • success: A Backbone-style success callback. + *
  • error: An Backbone-style error callback. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * @return {Parse.Promise} A promise that is fulfilled when the save + * completes. + */ + + }, { + key: 'save', + value: function (arg1, arg2, arg3) { + var _this = this; + + var attrs; + var options; + if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object' || typeof arg1 === 'undefined') { + attrs = arg1; + if ((typeof arg2 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg2)) === 'object') { + options = arg2; + } + } else { + attrs = {}; + attrs[arg1] = arg2; + options = arg3; + } + + // Support save({ success: function() {}, error: function() {} }) + if (!options && attrs) { + options = {}; + if (typeof attrs.success === 'function') { + options.success = attrs.success; + delete attrs.success; + } + if (typeof attrs.error === 'function') { + options.error = attrs.error; + delete attrs.error; + } + } + + if (attrs) { + var validation = this.validate(attrs); + if (validation) { + if (options && typeof options.error === 'function') { + options.error(this, validation); + } + return _ParsePromise2.default.error(validation); + } + this.set(attrs, options); + } + + options = options || {}; + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = !!options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { + saveOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getObjectController(); + var unsaved = (0, _unsavedChildren2.default)(this); + return controller.save(unsaved, saveOptions).then(function () { + return controller.save(_this, saveOptions); + })._thenRunCallbacks(options, this); + } + + /** + * Destroy this model on the server if it was already persisted. + * If `wait: true` is passed, waits for the server to respond + * before removal. + * + * @method destroy + * @param {Object} options A Backbone-style callback object. + * Valid options are:
    + *
  • success: A Backbone-style success callback + *
  • error: An Backbone-style error callback. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * @return {Parse.Promise} A promise that is fulfilled when the destroy + * completes. + */ + + }, { + key: 'destroy', + value: function (options) { + options = options || {}; + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + if (!this.id) { + return _ParsePromise2.default.as()._thenRunCallbacks(options); + } + return _CoreManager2.default.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); + } + + /** Static methods **/ + + }, { + key: 'attributes', + get: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return (0, _freeze2.default)(stateController.estimateAttributes(this._getStateIdentifier())); + } + + /** + * The first time this object was saved on the server. + * @property createdAt + * @type Date + */ + + }, { + key: 'createdAt', + get: function () { + return this._getServerData().createdAt; + } + + /** + * The last time this object was updated on the server. + * @property updatedAt + * @type Date + */ + + }, { + key: 'updatedAt', + get: function () { + return this._getServerData().updatedAt; + } + }], [{ + key: '_clearAllState', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.clearAllState(); + } + + /** + * Fetches the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
+     *   Parse.Object.fetchAll([object1, object2, ...], {
+     *     success: function(list) {
+     *       // All the objects were fetched.
+     *     },
+     *     error: function(error) {
+     *       // An error occurred while fetching one of the objects.
+     *     },
+     *   });
+     * 
+ * + * @method fetchAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
    + *
  • success: A Backbone-style success callback. + *
  • error: An Backbone-style error callback. + *
+ */ + + }, { + key: 'fetchAll', + value: function (list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); + } + + /** + * Fetches the given list of Parse.Object if needed. + * If any error is encountered, stops and calls the error handler. + * + *
+     *   Parse.Object.fetchAllIfNeeded([object1, ...], {
+     *     success: function(list) {
+     *       // Objects were fetched and updated.
+     *     },
+     *     error: function(error) {
+     *       // An error occurred while fetching one of the objects.
+     *     },
+     *   });
+     * 
+ * + * @method fetchAllIfNeeded + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
    + *
  • success: A Backbone-style success callback. + *
  • error: An Backbone-style error callback. + *
+ */ + + }, { + key: 'fetchAllIfNeeded', + value: function (list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); + } + + /** + * Destroy the given list of models on the server if it was already persisted. + * + *

Unlike saveAll, if an error occurs while deleting an individual model, + * this method will continue trying to delete the rest of the models if + * possible, except in the case of a fatal error like a connection error. + * + *

In particular, the Parse.Error object returned in the case of error may + * be one of two types: + * + *

    + *
  • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an + * array of other Parse.Error objects. Each error object in this array + * has an "object" property that references the object that could not be + * deleted (for instance, because that object could not be found).
  • + *
  • A non-aggregate Parse.Error. This indicates a serious error that + * caused the delete operation to be aborted partway through (for + * instance, a connection failure in the middle of the delete).
  • + *
+ * + *
+     *   Parse.Object.destroyAll([object1, object2, ...], {
+     *     success: function() {
+     *       // All the objects were deleted.
+     *     },
+     *     error: function(error) {
+     *       // An error occurred while deleting one or more of the objects.
+     *       // If this is an aggregate error, then we can inspect each error
+     *       // object individually to determine the reason why a particular
+     *       // object was not deleted.
+     *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
+     *         for (var i = 0; i < error.errors.length; i++) {
+     *           console.log("Couldn't delete " + error.errors[i].object.id +
+     *             "due to " + error.errors[i].message);
+     *         }
+     *       } else {
+     *         console.log("Delete aborted because of " + error.message);
+     *       }
+     *     },
+     *   });
+     * 
+ * + * @method destroyAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
    + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * @return {Parse.Promise} A promise that is fulfilled when the destroyAll + * completes. + */ + + }, { + key: 'destroyAll', + value: function (list, options) { + var options = options || {}; + + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); + } + + /** + * Saves the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
+     *   Parse.Object.saveAll([object1, object2, ...], {
+     *     success: function(list) {
+     *       // All the objects were saved.
+     *     },
+     *     error: function(error) {
+     *       // An error occurred while saving one of the objects.
+     *     },
+     *   });
+     * 
+ * + * @method saveAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
    + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ */ + + }, { + key: 'saveAll', + value: function (list, options) { + var options = options || {}; + + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + saveOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); + } + + /** + * Creates a reference to a subclass of Parse.Object with the given id. This + * does not exist on Parse.Object, only on subclasses. + * + *

A shortcut for:

+     *  var Foo = Parse.Object.extend("Foo");
+     *  var pointerToFoo = new Foo();
+     *  pointerToFoo.id = "myObjectId";
+     * 
+ * + * @method createWithoutData + * @param {String} id The ID of the object to create a reference to. + * @static + * @return {Parse.Object} A Parse.Object reference. + */ + + }, { + key: 'createWithoutData', + value: function (id) { + var obj = new this(); + obj.id = id; + return obj; + } + + /** + * Creates a new instance of a Parse Object from a JSON representation. + * @method fromJSON + * @param {Object} json The JSON map of the Object's data + * @param {boolean} override In single instance mode, all old server data + * is overwritten if this is set to true + * @static + * @return {Parse.Object} A Parse.Object reference + */ + + }, { + key: 'fromJSON', + value: function (json, override) { + if (!json.className) { + throw new Error('Cannot create an object without a className'); + } + var constructor = classMap[json.className]; + var o = constructor ? new constructor() : new ParseObject(json.className); + var otherAttributes = {}; + for (var attr in json) { + if (attr !== 'className' && attr !== '__type') { + otherAttributes[attr] = json[attr]; + } + } + if (override) { + // id needs to be set before clearServerData can work + if (otherAttributes.objectId) { + o.id = otherAttributes.objectId; + } + var preserved = null; + if (typeof o._preserveFieldsOnFetch === 'function') { + preserved = o._preserveFieldsOnFetch(); + } + o._clearServerData(); + if (preserved) { + o._finishFetch(preserved); + } + } + o._finishFetch(otherAttributes); + if (json.objectId) { + o._setExisted(true); + } + return o; + } + + /** + * Registers a subclass of Parse.Object with a specific class name. + * When objects of that class are retrieved from a query, they will be + * instantiated with this subclass. + * This is only necessary when using ES6 subclassing. + * @method registerSubclass + * @param {String} className The class name of the subclass + * @param {Class} constructor The subclass + */ + + }, { + key: 'registerSubclass', + value: function (className, constructor) { + if (typeof className !== 'string') { + throw new TypeError('The first argument must be a valid class name.'); + } + if (typeof constructor === 'undefined') { + throw new TypeError('You must supply a subclass constructor.'); + } + if (typeof constructor !== 'function') { + throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); + } + classMap[className] = constructor; + if (!constructor.className) { + constructor.className = className; + } + } + + /** + * Creates a new subclass of Parse.Object for the given Parse class name. + * + *

Every extension of a Parse class will inherit from the most recent + * previous extension of that class. When a Parse.Object is automatically + * created by parsing JSON, it will use the most recent extension of that + * class.

+ * + *

You should call either:

+     *     var MyClass = Parse.Object.extend("MyClass", {
+     *         Instance methods,
+     *         initialize: function(attrs, options) {
+     *             this.someInstanceProperty = [],
+     *             Other instance properties
+     *         }
+     *     }, {
+     *         Class properties
+     *     });
+ * or, for Backbone compatibility:
+     *     var MyClass = Parse.Object.extend({
+     *         className: "MyClass",
+     *         Instance methods,
+     *         initialize: function(attrs, options) {
+     *             this.someInstanceProperty = [],
+     *             Other instance properties
+     *         }
+     *     }, {
+     *         Class properties
+     *     });

+ * + * @method extend + * @param {String} className The name of the Parse class backing this model. + * @param {Object} protoProps Instance properties to add to instances of the + * class returned from this method. + * @param {Object} classProps Class properties to add the class returned from + * this method. + * @return {Class} A new subclass of Parse.Object. + */ + + }, { + key: 'extend', + value: function (className, protoProps, classProps) { + if (typeof className !== 'string') { + if (className && typeof className.className === 'string') { + return ParseObject.extend(className.className, className, protoProps); + } else { + throw new Error('Parse.Object.extend\'s first argument should be the className.'); + } + } + var adjustedClassName = className; + + if (adjustedClassName === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { + adjustedClassName = '_User'; + } + + var parentProto = ParseObject.prototype; + if (this.hasOwnProperty('__super__') && this.__super__) { + parentProto = this.prototype; + } else if (classMap[adjustedClassName]) { + parentProto = classMap[adjustedClassName].prototype; + } + var ParseObjectSubclass = function (attributes, options) { + this.className = adjustedClassName; + this._objCount = objectCount++; + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!this.set(attributes || {}, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + }; + ParseObjectSubclass.className = adjustedClassName; + ParseObjectSubclass.__super__ = parentProto; + + ParseObjectSubclass.prototype = (0, _create2.default)(parentProto, { + constructor: { + value: ParseObjectSubclass, + enumerable: false, + writable: true, + configurable: true + } + }); + + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseObjectSubclass.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseObjectSubclass, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + ParseObjectSubclass.extend = function (name, protoProps, classProps) { + if (typeof name === 'string') { + return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); + } + return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); + }; + ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; + + classMap[adjustedClassName] = ParseObjectSubclass; + return ParseObjectSubclass; + } + + /** + * Enable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * This is disabled by default in server environments, since it can lead to + * security issues. + * @method enableSingleInstance + */ + + }, { + key: 'enableSingleInstance', + value: function () { + singleInstance = true; + _CoreManager2.default.setObjectStateController(SingleInstanceStateController); + } + + /** + * Disable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * When disabled, you can have two instances of the same object in memory + * without them sharing attributes. + * @method disableSingleInstance + */ + + }, { + key: 'disableSingleInstance', + value: function () { + singleInstance = false; + _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); + } + }]); + return ParseObject; +}(); + +exports.default = ParseObject; + +var DefaultController = { + fetch: function (target, forceFetch, options) { + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + var objs = []; + var ids = []; + var className = null; + var results = []; + var error = null; + target.forEach(function (el, i) { + if (error) { + return; + } + if (!className) { + className = el.className; + } + if (className !== el.className) { + error = new _ParseError2.default(_ParseError2.default.INVALID_CLASS_NAME, 'All objects should be of the same class'); + } + if (!el.id) { + error = new _ParseError2.default(_ParseError2.default.MISSING_OBJECT_ID, 'All objects must have an ID'); + } + if (forceFetch || (0, _keys2.default)(el._getServerData()).length === 0) { + ids.push(el.id); + objs.push(el); + } + results.push(el); + }); + if (error) { + return _ParsePromise2.default.error(error); + } + var query = new _ParseQuery2.default(className); + query.containedIn('objectId', ids); + query._limit = ids.length; + return query.find(options).then(function (objects) { + var idMap = {}; + objects.forEach(function (o) { + idMap[o.id] = o; + }); + for (var i = 0; i < objs.length; i++) { + var obj = objs[i]; + if (!obj || !obj.id || !idMap[obj.id]) { + if (forceFetch) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); + } + } + } + if (!singleInstance) { + // If single instance objects are disabled, we need to replace the + for (var i = 0; i < results.length; i++) { + var obj = results[i]; + if (obj && obj.id && idMap[obj.id]) { + var id = obj.id; + obj._finishFetch(idMap[id].toJSON()); + results[i] = idMap[id]; + } + } + } + return _ParsePromise2.default.as(results); + }); + } else { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function (response, status, xhr) { + if (target instanceof ParseObject) { + target._clearPendingOps(); + target._clearServerData(); + target._finishFetch(response); + } + return target; + }); + } + }, + destroy: function (target, options) { + var RESTController = _CoreManager2.default.getRESTController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + var batches = [[]]; + target.forEach(function (obj) { + if (!obj.id) { + return; + } + batches[batches.length - 1].push(obj); + if (batches[batches.length - 1].length >= 20) { + batches.push([]); + } + }); + if (batches[batches.length - 1].length === 0) { + // If the last batch is empty, remove it + batches.pop(); + } + var deleteCompleted = _ParsePromise2.default.as(); + var errors = []; + batches.forEach(function (batch) { + deleteCompleted = deleteCompleted.then(function () { + return RESTController.request('POST', 'batch', { + requests: batch.map(function (obj) { + return { + method: 'DELETE', + path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), + body: {} + }; + }) + }, options).then(function (results) { + for (var i = 0; i < results.length; i++) { + if (results[i] && results[i].hasOwnProperty('error')) { + var err = new _ParseError2.default(results[i].error.code, results[i].error.error); + err.object = batch[i]; + errors.push(err); + } + } + }); + }); + }); + return deleteCompleted.then(function () { + if (errors.length) { + var aggregate = new _ParseError2.default(_ParseError2.default.AGGREGATE_ERROR); + aggregate.errors = errors; + return _ParsePromise2.default.error(aggregate); + } + return _ParsePromise2.default.as(target); + }); + } else if (target instanceof ParseObject) { + return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function () { + return _ParsePromise2.default.as(target); + }); + } + return _ParsePromise2.default.as(target); + }, + save: function (target, options) { + var RESTController = _CoreManager2.default.getRESTController(); + var stateController = _CoreManager2.default.getObjectStateController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + + var unsaved = target.concat(); + for (var i = 0; i < target.length; i++) { + if (target[i] instanceof ParseObject) { + unsaved = unsaved.concat((0, _unsavedChildren2.default)(target[i], true)); + } + } + unsaved = (0, _unique2.default)(unsaved); + + var filesSaved = _ParsePromise2.default.as(); + var pending = []; + unsaved.forEach(function (el) { + if (el instanceof _ParseFile2.default) { + filesSaved = filesSaved.then(function () { + return el.save(); + }); + } else if (el instanceof ParseObject) { + pending.push(el); + } + }); + + return filesSaved.then(function () { + var objectError = null; + return _ParsePromise2.default._continueWhile(function () { + return pending.length > 0; + }, function () { + var batch = []; + var nextPending = []; + pending.forEach(function (el) { + if (batch.length < 20 && (0, _canBeSerialized2.default)(el)) { + batch.push(el); + } else { + nextPending.push(el); + } + }); + pending = nextPending; + if (batch.length < 1) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); + } + + // Queue up tasks for each object in the batch. + // When every task is ready, the API request will execute + var batchReturned = new _ParsePromise2.default(); + var batchReady = []; + var batchTasks = []; + batch.forEach(function (obj, index) { + var ready = new _ParsePromise2.default(); + batchReady.push(ready); + + stateController.pushPendingState(obj._getStateIdentifier()); + batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { + ready.resolve(); + return batchReturned.then(function (responses, status) { + if (responses[index].hasOwnProperty('success')) { + obj._handleSaveResponse(responses[index].success, status); + } else { + if (!objectError && responses[index].hasOwnProperty('error')) { + var serverError = responses[index].error; + objectError = new _ParseError2.default(serverError.code, serverError.error); + // Cancel the rest of the save + pending = []; + } + obj._handleSaveError(); + } + }); + })); + }); + + _ParsePromise2.default.when(batchReady).then(function () { + // Kick off the batch request + return RESTController.request('POST', 'batch', { + requests: batch.map(function (obj) { + var params = obj._getSaveParams(); + params.path = getServerUrlPath() + params.path; + return params; + }) + }, options); + }).then(function (response, status, xhr) { + batchReturned.resolve(response, status); + }); + + return _ParsePromise2.default.when(batchTasks); + }).then(function () { + if (objectError) { + return _ParsePromise2.default.error(objectError); + } + return _ParsePromise2.default.as(target); + }); + }); + } else if (target instanceof ParseObject) { + // copying target lets Flow guarantee the pointer isn't modified elsewhere + var targetCopy = target; + var task = function () { + var params = targetCopy._getSaveParams(); + return RESTController.request(params.method, params.path, params.body, options).then(function (response, status) { + targetCopy._handleSaveResponse(response, status); + }, function (error) { + targetCopy._handleSaveError(); + return _ParsePromise2.default.error(error); + }); + }; + + stateController.pushPendingState(target._getStateIdentifier()); + return stateController.enqueueTask(target._getStateIdentifier(), task).then(function () { + return target; + }, function (error) { + return _ParsePromise2.default.error(error); + }); + } + return _ParsePromise2.default.as(); + } +}; + +_CoreManager2.default.setObjectController(DefaultController); +},{"./CoreManager":3,"./ParseACL":11,"./ParseError":13,"./ParseFile":14,"./ParseOp":19,"./ParsePromise":20,"./ParseQuery":21,"./ParseRelation":22,"./SingleInstanceStateController":28,"./UniqueInstanceStateController":32,"./canBeSerialized":34,"./decode":35,"./encode":36,"./equals":37,"./escape":38,"./parseDate":40,"./unique":41,"./unsavedChildren":42,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/object/create":46,"babel-runtime/core-js/object/define-property":47,"babel-runtime/core-js/object/freeze":48,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],19:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.RelationOp = exports.RemoveOp = exports.AddUniqueOp = exports.AddOp = exports.IncrementOp = exports.UnsetOp = exports.SetOp = exports.Op = undefined; + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +exports.opFromJSON = opFromJSON; + +var _arrayContainsObject = _dereq_('./arrayContainsObject'); + +var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); + +var _decode = _dereq_('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _unique = _dereq_('./unique'); + +var _unique2 = _interopRequireDefault(_unique); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function opFromJSON(json) { + if (!json || !json.__op) { + return null; + } + switch (json.__op) { + case 'Delete': + return new UnsetOp(); + case 'Increment': + return new IncrementOp(json.amount); + case 'Add': + return new AddOp((0, _decode2.default)(json.objects)); + case 'AddUnique': + return new AddUniqueOp((0, _decode2.default)(json.objects)); + case 'Remove': + return new RemoveOp((0, _decode2.default)(json.objects)); + case 'AddRelation': + var toAdd = (0, _decode2.default)(json.objects); + if (!Array.isArray(toAdd)) { + return new RelationOp([], []); + } + return new RelationOp(toAdd, []); + case 'RemoveRelation': + var toRemove = (0, _decode2.default)(json.objects); + if (!Array.isArray(toRemove)) { + return new RelationOp([], []); + } + return new RelationOp([], toRemove); + case 'Batch': + var toAdd = []; + var toRemove = []; + for (var i = 0; i < json.ops.length; i++) { + if (json.ops[i].__op === 'AddRelation') { + toAdd = toAdd.concat((0, _decode2.default)(json.ops[i].objects)); + } else if (json.ops[i].__op === 'RemoveRelation') { + toRemove = toRemove.concat((0, _decode2.default)(json.ops[i].objects)); + } + } + return new RelationOp(toAdd, toRemove); + } + return null; +} + +var Op = exports.Op = function () { + function Op() { + (0, _classCallCheck3.default)(this, Op); + } + + (0, _createClass3.default)(Op, [{ + key: 'applyTo', + + // Empty parent class + value: function (value) {} + }, { + key: 'mergeWith', + value: function (previous) {} + }, { + key: 'toJSON', + value: function () {} + }]); + return Op; +}(); + +var SetOp = exports.SetOp = function (_Op) { + (0, _inherits3.default)(SetOp, _Op); + + function SetOp(value) { + (0, _classCallCheck3.default)(this, SetOp); + + var _this = (0, _possibleConstructorReturn3.default)(this, (SetOp.__proto__ || (0, _getPrototypeOf2.default)(SetOp)).call(this)); + + _this._value = value; + return _this; + } + + (0, _createClass3.default)(SetOp, [{ + key: 'applyTo', + value: function (value) { + return this._value; + } + }, { + key: 'mergeWith', + value: function (previous) { + return new SetOp(this._value); + } + }, { + key: 'toJSON', + value: function () { + return (0, _encode2.default)(this._value, false, true); + } + }]); + return SetOp; +}(Op); + +var UnsetOp = exports.UnsetOp = function (_Op2) { + (0, _inherits3.default)(UnsetOp, _Op2); + + function UnsetOp() { + (0, _classCallCheck3.default)(this, UnsetOp); + return (0, _possibleConstructorReturn3.default)(this, (UnsetOp.__proto__ || (0, _getPrototypeOf2.default)(UnsetOp)).apply(this, arguments)); + } + + (0, _createClass3.default)(UnsetOp, [{ + key: 'applyTo', + value: function (value) { + return undefined; + } + }, { + key: 'mergeWith', + value: function (previous) { + return new UnsetOp(); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Delete' }; + } + }]); + return UnsetOp; +}(Op); + +var IncrementOp = exports.IncrementOp = function (_Op3) { + (0, _inherits3.default)(IncrementOp, _Op3); + + function IncrementOp(amount) { + (0, _classCallCheck3.default)(this, IncrementOp); + + var _this3 = (0, _possibleConstructorReturn3.default)(this, (IncrementOp.__proto__ || (0, _getPrototypeOf2.default)(IncrementOp)).call(this)); + + if (typeof amount !== 'number') { + throw new TypeError('Increment Op must be initialized with a numeric amount.'); + } + _this3._amount = amount; + return _this3; + } + + (0, _createClass3.default)(IncrementOp, [{ + key: 'applyTo', + value: function (value) { + if (typeof value === 'undefined') { + return this._amount; + } + if (typeof value !== 'number') { + throw new TypeError('Cannot increment a non-numeric value.'); + } + return this._amount + value; + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._amount); + } + if (previous instanceof IncrementOp) { + return new IncrementOp(this.applyTo(previous._amount)); + } + throw new Error('Cannot merge Increment Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Increment', amount: this._amount }; + } + }]); + return IncrementOp; +}(Op); + +var AddOp = exports.AddOp = function (_Op4) { + (0, _inherits3.default)(AddOp, _Op4); + + function AddOp(value) { + (0, _classCallCheck3.default)(this, AddOp); + + var _this4 = (0, _possibleConstructorReturn3.default)(this, (AddOp.__proto__ || (0, _getPrototypeOf2.default)(AddOp)).call(this)); + + _this4._value = Array.isArray(value) ? value : [value]; + return _this4; + } + + (0, _createClass3.default)(AddOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return this._value; + } + if (Array.isArray(value)) { + return value.concat(this._value); + } + throw new Error('Cannot add elements to a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddOp) { + return new AddOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge Add Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Add', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return AddOp; +}(Op); + +var AddUniqueOp = exports.AddUniqueOp = function (_Op5) { + (0, _inherits3.default)(AddUniqueOp, _Op5); + + function AddUniqueOp(value) { + (0, _classCallCheck3.default)(this, AddUniqueOp); + + var _this5 = (0, _possibleConstructorReturn3.default)(this, (AddUniqueOp.__proto__ || (0, _getPrototypeOf2.default)(AddUniqueOp)).call(this)); + + _this5._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); + return _this5; + } + + (0, _createClass3.default)(AddUniqueOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return this._value || []; + } + if (Array.isArray(value)) { + // copying value lets Flow guarantee the pointer isn't modified elsewhere + var valueCopy = value; + var toAdd = []; + this._value.forEach(function (v) { + if (v instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(valueCopy, v)) { + toAdd.push(v); + } + } else { + if (valueCopy.indexOf(v) < 0) { + toAdd.push(v); + } + } + }); + return value.concat(toAdd); + } + throw new Error('Cannot add elements to a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddUniqueOp) { + return new AddUniqueOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge AddUnique Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'AddUnique', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return AddUniqueOp; +}(Op); + +var RemoveOp = exports.RemoveOp = function (_Op6) { + (0, _inherits3.default)(RemoveOp, _Op6); + + function RemoveOp(value) { + (0, _classCallCheck3.default)(this, RemoveOp); + + var _this6 = (0, _possibleConstructorReturn3.default)(this, (RemoveOp.__proto__ || (0, _getPrototypeOf2.default)(RemoveOp)).call(this)); + + _this6._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); + return _this6; + } + + (0, _createClass3.default)(RemoveOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return []; + } + if (Array.isArray(value)) { + var i = value.indexOf(this._value); + var removed = value.concat([]); + for (var i = 0; i < this._value.length; i++) { + var index = removed.indexOf(this._value[i]); + while (index > -1) { + removed.splice(index, 1); + index = removed.indexOf(this._value[i]); + } + if (this._value[i] instanceof _ParseObject2.default && this._value[i].id) { + for (var j = 0; j < removed.length; j++) { + if (removed[j] instanceof _ParseObject2.default && this._value[i].id === removed[j].id) { + removed.splice(j, 1); + j--; + } + } + } + } + return removed; + } + throw new Error('Cannot remove elements from a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new UnsetOp(); + } + if (previous instanceof RemoveOp) { + var uniques = previous._value.concat([]); + for (var i = 0; i < this._value.length; i++) { + if (this._value[i] instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(uniques, this._value[i])) { + uniques.push(this._value[i]); + } + } else { + if (uniques.indexOf(this._value[i]) < 0) { + uniques.push(this._value[i]); + } + } + } + return new RemoveOp(uniques); + } + throw new Error('Cannot merge Remove Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Remove', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return RemoveOp; +}(Op); + +var RelationOp = exports.RelationOp = function (_Op7) { + (0, _inherits3.default)(RelationOp, _Op7); + + function RelationOp(adds, removes) { + (0, _classCallCheck3.default)(this, RelationOp); + + var _this7 = (0, _possibleConstructorReturn3.default)(this, (RelationOp.__proto__ || (0, _getPrototypeOf2.default)(RelationOp)).call(this)); + + _this7._targetClassName = null; + + if (Array.isArray(adds)) { + _this7.relationsToAdd = (0, _unique2.default)(adds.map(_this7._extractId, _this7)); + } + + if (Array.isArray(removes)) { + _this7.relationsToRemove = (0, _unique2.default)(removes.map(_this7._extractId, _this7)); + } + return _this7; + } + + (0, _createClass3.default)(RelationOp, [{ + key: '_extractId', + value: function (obj) { + if (typeof obj === 'string') { + return obj; + } + if (!obj.id) { + throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); + } + if (!this._targetClassName) { + this._targetClassName = obj.className; + } + if (this._targetClassName !== obj.className) { + throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); + } + return obj.id; + } + }, { + key: 'applyTo', + value: function (value, object, key) { + if (!value) { + if (!object || !key) { + throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); + } + var parent = new _ParseObject2.default(object.className); + if (object.id && object.id.indexOf('local') === 0) { + parent._localId = object.id; + } else if (object.id) { + parent.id = object.id; + } + var relation = new _ParseRelation2.default(parent, key); + relation.targetClassName = this._targetClassName; + return relation; + } + if (value instanceof _ParseRelation2.default) { + if (this._targetClassName) { + if (value.targetClassName) { + if (this._targetClassName !== value.targetClassName) { + throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); + } + } else { + value.targetClassName = this._targetClassName; + } + } + return value; + } else { + throw new Error('Relation cannot be applied to a non-relation field'); + } + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } else if (previous instanceof UnsetOp) { + throw new Error('You cannot modify a relation after deleting it.'); + } else if (previous instanceof RelationOp) { + if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { + throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); + } + var newAdd = previous.relationsToAdd.concat([]); + this.relationsToRemove.forEach(function (r) { + var index = newAdd.indexOf(r); + if (index > -1) { + newAdd.splice(index, 1); + } + }); + this.relationsToAdd.forEach(function (r) { + var index = newAdd.indexOf(r); + if (index < 0) { + newAdd.push(r); + } + }); + + var newRemove = previous.relationsToRemove.concat([]); + this.relationsToAdd.forEach(function (r) { + var index = newRemove.indexOf(r); + if (index > -1) { + newRemove.splice(index, 1); + } + }); + this.relationsToRemove.forEach(function (r) { + var index = newRemove.indexOf(r); + if (index < 0) { + newRemove.push(r); + } + }); + + var newRelation = new RelationOp(newAdd, newRemove); + newRelation._targetClassName = this._targetClassName; + return newRelation; + } + throw new Error('Cannot merge Relation Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + var _this8 = this; + + var idToPointer = function (id) { + return { + __type: 'Pointer', + className: _this8._targetClassName, + objectId: id + }; + }; + + var adds = null; + var removes = null; + var pointers = null; + + if (this.relationsToAdd.length > 0) { + pointers = this.relationsToAdd.map(idToPointer); + adds = { __op: 'AddRelation', objects: pointers }; + } + if (this.relationsToRemove.length > 0) { + pointers = this.relationsToRemove.map(idToPointer); + removes = { __op: 'RemoveRelation', objects: pointers }; + } + + if (adds && removes) { + return { __op: 'Batch', ops: [adds, removes] }; + } + + return adds || removes || {}; + } + }]); + return RelationOp; +}(Op); +},{"./ParseObject":18,"./ParseRelation":22,"./arrayContainsObject":33,"./decode":35,"./encode":36,"./unique":41,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],20:[function(_dereq_,module,exports){ +(function (process){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getIterator2 = _dereq_('babel-runtime/core-js/get-iterator'); + +var _getIterator3 = _interopRequireDefault(_getIterator2); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var _isPromisesAPlusCompliant = true; + +/** + * A Promise is returned by async methods as a hook to provide callbacks to be + * called when the async task is fulfilled. + * + *

Typical usage would be like:

+ *    query.find().then(function(results) {
+ *      results[0].set("foo", "bar");
+ *      return results[0].saveAsync();
+ *    }).then(function(result) {
+ *      console.log("Updated " + result.id);
+ *    });
+ * 

+ * + * @class Parse.Promise + * @constructor + */ + +var ParsePromise = function () { + function ParsePromise(executor) { + (0, _classCallCheck3.default)(this, ParsePromise); + + this._resolved = false; + this._rejected = false; + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + + if (typeof executor === 'function') { + executor(this.resolve.bind(this), this.reject.bind(this)); + } + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method resolve + * @param {Object} result the result to pass to the callbacks. + */ + + (0, _createClass3.default)(ParsePromise, [{ + key: 'resolve', + value: function () { + if (this._resolved || this._rejected) { + throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._resolved = true; + + for (var _len = arguments.length, results = Array(_len), _key = 0; _key < _len; _key++) { + results[_key] = arguments[_key]; + } + + this._result = results; + for (var i = 0; i < this._resolvedCallbacks.length; i++) { + this._resolvedCallbacks[i].apply(this, results); + } + + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method reject + * @param {Object} error the error to pass to the callbacks. + */ + + }, { + key: 'reject', + value: function (error) { + if (this._resolved || this._rejected) { + throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._rejected = true; + this._error = error; + for (var i = 0; i < this._rejectedCallbacks.length; i++) { + this._rejectedCallbacks[i](error); + } + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Adds callbacks to be called when this promise is fulfilled. Returns a new + * Promise that will be fulfilled when the callback is complete. It allows + * chaining. If the callback itself returns a Promise, then the one returned + * by "then" will not be fulfilled until that one returned by the callback + * is fulfilled. + * @method then + * @param {Function} resolvedCallback Function that is called when this + * Promise is resolved. Once the callback is complete, then the Promise + * returned by "then" will also be fulfilled. + * @param {Function} rejectedCallback Function that is called when this + * Promise is rejected with an error. Once the callback is complete, then + * the promise returned by "then" with be resolved successfully. If + * rejectedCallback is null, or it returns a rejected Promise, then the + * Promise returned by "then" will be rejected with that error. + * @return {Parse.Promise} A new Promise that will be fulfilled after this + * Promise is fulfilled and either callback has completed. If the callback + * returned a Promise, then this Promise will not be fulfilled until that + * one is. + */ + + }, { + key: 'then', + value: function (resolvedCallback, rejectedCallback) { + var _this = this; + + var promise = new ParsePromise(); + + var wrappedResolvedCallback = function () { + for (var _len2 = arguments.length, results = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + results[_key2] = arguments[_key2]; + } + + if (typeof resolvedCallback === 'function') { + if (_isPromisesAPlusCompliant) { + try { + results = [resolvedCallback.apply(this, results)]; + } catch (e) { + results = [ParsePromise.error(e)]; + } + } else { + results = [resolvedCallback.apply(this, results)]; + } + } + if (results.length === 1 && ParsePromise.is(results[0])) { + results[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + promise.resolve.apply(promise, results); + } + }; + + var wrappedRejectedCallback = function (error) { + var result = []; + if (typeof rejectedCallback === 'function') { + if (_isPromisesAPlusCompliant) { + try { + result = [rejectedCallback(error)]; + } catch (e) { + result = [ParsePromise.error(e)]; + } + } else { + result = [rejectedCallback(error)]; + } + if (result.length === 1 && ParsePromise.is(result[0])) { + result[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + if (_isPromisesAPlusCompliant) { + promise.resolve.apply(promise, result); + } else { + promise.reject(result[0]); + } + } + } else { + promise.reject(error); + } + }; + + var runLater = function (fn) { + fn.call(); + }; + if (_isPromisesAPlusCompliant) { + if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { + runLater = function (fn) { + process.nextTick(fn); + }; + } else if (typeof setTimeout === 'function') { + runLater = function (fn) { + setTimeout(fn, 0); + }; + } + } + + if (this._resolved) { + runLater(function () { + wrappedResolvedCallback.apply(_this, _this._result); + }); + } else if (this._rejected) { + runLater(function () { + wrappedRejectedCallback(_this._error); + }); + } else { + this._resolvedCallbacks.push(wrappedResolvedCallback); + this._rejectedCallbacks.push(wrappedRejectedCallback); + } + + return promise; + } + + /** + * Add handlers to be called when the promise + * is either resolved or rejected + * @method always + */ + + }, { + key: 'always', + value: function (callback) { + return this.then(callback, callback); + } + + /** + * Add handlers to be called when the Promise object is resolved + * @method done + */ + + }, { + key: 'done', + value: function (callback) { + return this.then(callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * Alias for catch(). + * @method fail + */ + + }, { + key: 'fail', + value: function (callback) { + return this.then(null, callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * @method catch + */ + + }, { + key: 'catch', + value: function (callback) { + return this.then(null, callback); + } + + /** + * Run the given callbacks after this promise is fulfilled. + * @method _thenRunCallbacks + * @param optionsOrCallback {} A Backbone-style options callback, or a + * callback function. If this is an options object and contains a "model" + * attributes, that will be passed to error callbacks as the first argument. + * @param model {} If truthy, this will be passed as the first result of + * error callbacks. This is for Backbone-compatability. + * @return {Parse.Promise} A promise that will be resolved after the + * callbacks are run, with the same result as this. + */ + + }, { + key: '_thenRunCallbacks', + value: function (optionsOrCallback, model) { + var options = {}; + if (typeof optionsOrCallback === 'function') { + options.success = function (result) { + optionsOrCallback(result, null); + }; + options.error = function (error) { + optionsOrCallback(null, error); + }; + } else if ((typeof optionsOrCallback === 'undefined' ? 'undefined' : (0, _typeof3.default)(optionsOrCallback)) === 'object') { + if (typeof optionsOrCallback.success === 'function') { + options.success = optionsOrCallback.success; + } + if (typeof optionsOrCallback.error === 'function') { + options.error = optionsOrCallback.error; + } + } + + return this.then(function () { + for (var _len3 = arguments.length, results = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + results[_key3] = arguments[_key3]; + } + + if (options.success) { + options.success.apply(this, results); + } + return ParsePromise.as.apply(ParsePromise, arguments); + }, function (error) { + if (options.error) { + if (typeof model !== 'undefined') { + options.error(model, error); + } else { + options.error(error); + } + } + // By explicitly returning a rejected Promise, this will work with + // either jQuery or Promises/A+ semantics. + return ParsePromise.error(error); + }); + } + + /** + * Adds a callback function that should be called regardless of whether + * this promise failed or succeeded. The callback will be given either the + * array of results for its first argument, or the error as its second, + * depending on whether this Promise was rejected or resolved. Returns a + * new Promise, like "then" would. + * @method _continueWith + * @param {Function} continuation the callback. + */ + + }, { + key: '_continueWith', + value: function (continuation) { + return this.then(function () { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + return continuation(args, null); + }, function (error) { + return continuation(null, error); + }); + } + + /** + * Returns true iff the given object fulfils the Promise interface. + * @method is + * @param {Object} promise The object to test + * @static + * @return {Boolean} + */ + + }], [{ + key: 'is', + value: function (promise) { + return promise != null && typeof promise.then === 'function'; + } + + /** + * Returns a new promise that is resolved with a given value. + * @method as + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'as', + value: function () { + var promise = new ParsePromise(); + + for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + values[_key5] = arguments[_key5]; + } + + promise.resolve.apply(promise, values); + return promise; + } + + /** + * Returns a new promise that is resolved with a given value. + * If that value is a thenable Promise (has a .then() prototype + * method), the new promise will be chained to the end of the + * value. + * @method resolve + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'resolve', + value: function (value) { + return new ParsePromise(function (resolve, reject) { + if (ParsePromise.is(value)) { + value.then(resolve, reject); + } else { + resolve(value); + } + }); + } + + /** + * Returns a new promise that is rejected with a given error. + * @method error + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'error', + value: function () { + var promise = new ParsePromise(); + + for (var _len6 = arguments.length, errors = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + errors[_key6] = arguments[_key6]; + } + + promise.reject.apply(promise, errors); + return promise; + } + + /** + * Returns a new promise that is rejected with a given error. + * This is an alias for Parse.Promise.error, for compliance with + * the ES6 implementation. + * @method reject + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'reject', + value: function () { + for (var _len7 = arguments.length, errors = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + errors[_key7] = arguments[_key7]; + } + + return ParsePromise.error.apply(null, errors); + } + + /** + * Returns a new promise that is fulfilled when all of the input promises + * are resolved. If any promise in the list fails, then the returned promise + * will be rejected with an array containing the error from each promise. + * If they all succeed, then the returned promise will succeed, with the + * results being the results of all the input + * promises. For example:
+     *   var p1 = Parse.Promise.as(1);
+     *   var p2 = Parse.Promise.as(2);
+     *   var p3 = Parse.Promise.as(3);
+     *
+     *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
+     *     console.log(r1);  // prints 1
+     *     console.log(r2);  // prints 2
+     *     console.log(r3);  // prints 3
+     *   });
+ * + * The input promises can also be specified as an array:
+     *   var promises = [p1, p2, p3];
+     *   Parse.Promise.when(promises).then(function(results) {
+     *     console.log(results);  // prints [1,2,3]
+     *   });
+     * 
+ * @method when + * @param {Array} promises a list of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'when', + value: function (promises) { + var objects; + var arrayArgument = Array.isArray(promises); + if (arrayArgument) { + objects = promises; + } else { + objects = arguments; + } + + var total = objects.length; + var hadError = false; + var results = []; + var returnValue = arrayArgument ? [results] : results; + var errors = []; + results.length = objects.length; + errors.length = objects.length; + + if (total === 0) { + return ParsePromise.as.apply(this, returnValue); + } + + var promise = new ParsePromise(); + + var resolveOne = function () { + total--; + if (total <= 0) { + if (hadError) { + promise.reject(errors); + } else { + promise.resolve.apply(promise, returnValue); + } + } + }; + + var chain = function (object, index) { + if (ParsePromise.is(object)) { + object.then(function (result) { + results[index] = result; + resolveOne(); + }, function (error) { + errors[index] = error; + hadError = true; + resolveOne(); + }); + } else { + results[i] = object; + resolveOne(); + } + }; + for (var i = 0; i < objects.length; i++) { + chain(objects[i], i); + } + + return promise; + } + + /** + * Returns a new promise that is fulfilled when all of the promises in the + * iterable argument are resolved. If any promise in the list fails, then + * the returned promise will be immediately rejected with the reason that + * single promise rejected. If they all succeed, then the returned promise + * will succeed, with the results being the results of all the input + * promises. If the iterable provided is empty, the returned promise will + * be immediately resolved. + * + * For example:
+     *   var p1 = Parse.Promise.as(1);
+     *   var p2 = Parse.Promise.as(2);
+     *   var p3 = Parse.Promise.as(3);
+     *
+     *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
+     *     console.log(r1);  // prints 1
+     *     console.log(r2);  // prints 2
+     *     console.log(r3);  // prints 3
+     *   });
+ * + * @method all + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'all', + value: function (promises) { + var total = 0; + var objects = []; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = (0, _getIterator3.default)(promises), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var p = _step.value; + + objects[total++] = p; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (total === 0) { + return ParsePromise.as([]); + } + + var hadError = false; + var promise = new ParsePromise(); + var resolved = 0; + var results = []; + objects.forEach(function (object, i) { + if (ParsePromise.is(object)) { + object.then(function (result) { + if (hadError) { + return false; + } + results[i] = result; + resolved++; + if (resolved >= total) { + promise.resolve(results); + } + }, function (error) { + // Reject immediately + promise.reject(error); + hadError = true; + }); + } else { + results[i] = object; + resolved++; + if (!hadError && resolved >= total) { + promise.resolve(results); + } + } + }); + + return promise; + } + + /** + * Returns a new promise that is immediately fulfilled when any of the + * promises in the iterable argument are resolved or rejected. If the + * first promise to complete is resolved, the returned promise will be + * resolved with the same value. Likewise, if the first promise to + * complete is rejected, the returned promise will be rejected with the + * same reason. + * + * @method race + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'race', + value: function (promises) { + var completed = false; + var promise = new ParsePromise(); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = (0, _getIterator3.default)(promises), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var p = _step2.value; + + if (ParsePromise.is(p)) { + p.then(function (result) { + if (completed) { + return; + } + completed = true; + promise.resolve(result); + }, function (error) { + if (completed) { + return; + } + completed = true; + promise.reject(error); + }); + } else if (!completed) { + completed = true; + promise.resolve(p); + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return promise; + } + + /** + * Runs the given asyncFunction repeatedly, as long as the predicate + * function returns a truthy value. Stops repeating if asyncFunction returns + * a rejected promise. + * @method _continueWhile + * @param {Function} predicate should return false when ready to stop. + * @param {Function} asyncFunction should return a Promise. + * @static + */ + + }, { + key: '_continueWhile', + value: function (predicate, asyncFunction) { + if (predicate()) { + return asyncFunction().then(function () { + return ParsePromise._continueWhile(predicate, asyncFunction); + }); + } + return ParsePromise.as(); + } + }, { + key: 'isPromisesAPlusCompliant', + value: function () { + return _isPromisesAPlusCompliant; + } + }, { + key: 'enableAPlusCompliant', + value: function () { + _isPromisesAPlusCompliant = true; + } + }, { + key: 'disableAPlusCompliant', + value: function () { + _isPromisesAPlusCompliant = false; + } + }]); + return ParsePromise; +}(); + +exports.default = ParsePromise; +}).call(this,_dereq_('_process')) +},{"_process":168,"babel-runtime/core-js/get-iterator":43,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],21:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _keys = _dereq_('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _encode = _dereq_('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Converts a string into a regex that matches it. + * Surrounding with \Q .. \E does this, we just need to escape any \E's in + * the text separately. + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function quote(s) { + return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; +} + +/** + * Handles pre-populating the result data of a query with select fields, + * making sure that the data object contains keys for all objects that have + * been requested with a select, so that our cached state updates correctly. + */ +function handleSelectResult(data, select) { + var serverDataMask = {}; + + select.forEach(function (field) { + var hasSubObjectSelect = field.indexOf(".") !== -1; + if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { + // this field was selected, but is missing from the retrieved data + data[field] = undefined; + } else if (hasSubObjectSelect) { + // this field references a sub-object, + // so we need to walk down the path components + var pathComponents = field.split("."); + var obj = data; + var serverMask = serverDataMask; + + pathComponents.forEach(function (component, index, arr) { + // add keys if the expected data is missing + if (!obj[component]) { + obj[component] = index == arr.length - 1 ? undefined : {}; + } + obj = obj[component]; + + //add this path component to the server mask so we can fill it in later if needed + if (index < arr.length - 1) { + if (!serverMask[component]) { + serverMask[component] = {}; + } + } + }); + } + }); + + if ((0, _keys2.default)(serverDataMask).length > 0) { + var copyMissingDataWithMask = function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { + //copy missing elements at this level + if (copyThisLevel) { + for (var key in src) { + if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + } + for (var key in mask) { + //traverse into objects as needed + copyMissingDataWithMask(src[key], dest[key], mask[key], true); + } + }; + + // When selecting from sub-objects, we don't want to blow away the missing + // information that we may have retrieved before. We've already added any + // missing selected keys to sub-objects, but we still need to add in the + // data for any previously retrieved sub-objects that were not selected. + + var serverData = _CoreManager2.default.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); + + copyMissingDataWithMask(serverData, data, serverDataMask, false); + } +} + +/** + * Creates a new parse Parse.Query for the given Parse.Object subclass. + * @class Parse.Query + * @constructor + * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. + * + *

Parse.Query defines a query that is used to fetch Parse.Objects. The + * most common use case is finding all objects that match a query through the + * find method. For example, this sample code fetches all objects + * of class MyClass. It calls a different function depending on + * whether the fetch succeeded or not. + * + *

+ * var query = new Parse.Query(MyClass);
+ * query.find({
+ *   success: function(results) {
+ *     // results is an array of Parse.Object.
+ *   },
+ *
+ *   error: function(error) {
+ *     // error is an instance of Parse.Error.
+ *   }
+ * });

+ * + *

A Parse.Query can also be used to retrieve a single object whose id is + * known, through the get method. For example, this sample code fetches an + * object of class MyClass and id myId. It calls a + * different function depending on whether the fetch succeeded or not. + * + *

+ * var query = new Parse.Query(MyClass);
+ * query.get(myId, {
+ *   success: function(object) {
+ *     // object is an instance of Parse.Object.
+ *   },
+ *
+ *   error: function(object, error) {
+ *     // error is an instance of Parse.Error.
+ *   }
+ * });

+ * + *

A Parse.Query can also be used to count the number of objects that match + * the query without retrieving all of those objects. For example, this + * sample code counts the number of objects of the class MyClass + *

+ * var query = new Parse.Query(MyClass);
+ * query.count({
+ *   success: function(number) {
+ *     // There are number instances of MyClass.
+ *   },
+ *
+ *   error: function(error) {
+ *     // error is an instance of Parse.Error.
+ *   }
+ * });

+ */ + +var ParseQuery = function () { + function ParseQuery(objectClass) { + (0, _classCallCheck3.default)(this, ParseQuery); + + if (typeof objectClass === 'string') { + if (objectClass === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { + this.className = '_User'; + } else { + this.className = objectClass; + } + } else if (objectClass instanceof _ParseObject2.default) { + this.className = objectClass.className; + } else if (typeof objectClass === 'function') { + if (typeof objectClass.className === 'string') { + this.className = objectClass.className; + } else { + var obj = new objectClass(); + this.className = obj.className; + } + } else { + throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); + } + + this._where = {}; + this._include = []; + this._limit = -1; // negative limit is not sent in the server request + this._skip = 0; + this._extraOptions = {}; + } + + /** + * Adds constraint that at least one of the passed in queries matches. + * @method _orQuery + * @param {Array} queries + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + (0, _createClass3.default)(ParseQuery, [{ + key: '_orQuery', + value: function (queries) { + var queryJSON = queries.map(function (q) { + return q.toJSON().where; + }); + + this._where.$or = queryJSON; + return this; + } + + /** + * Helper for condition queries + */ + + }, { + key: '_addCondition', + value: function (key, condition, value) { + if (!this._where[key] || typeof this._where[key] === 'string') { + this._where[key] = {}; + } + this._where[key][condition] = (0, _encode2.default)(value, false, true); + return this; + } + + /** + * Converts string for regular expression at the beginning + */ + + }, { + key: '_regexStartWith', + value: function (string) { + return '^' + quote(string); + } + + /** + * Returns a JSON representation of this query. + * @method toJSON + * @return {Object} The JSON representation of the query. + */ + + }, { + key: 'toJSON', + value: function () { + var params = { + where: this._where + }; + + if (this._include.length) { + params.include = this._include.join(','); + } + if (this._select) { + params.keys = this._select.join(','); + } + if (this._limit >= 0) { + params.limit = this._limit; + } + if (this._skip > 0) { + params.skip = this._skip; + } + if (this._order) { + params.order = this._order.join(','); + } + for (var key in this._extraOptions) { + params[key] = this._extraOptions[key]; + } + + return params; + } + + /** + * Constructs a Parse.Object whose id is already known by fetching data from + * the server. Either options.success or options.error is called when the + * find completes. + * + * @method get + * @param {String} objectId The id of the object to be fetched. + * @param {Object} options A Backbone-style options object. + * Valid options are:
    + *
  • success: A Backbone-style success callback + *
  • error: An Backbone-style error callback. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * + * @return {Parse.Promise} A promise that is resolved with the result when + * the query completes. + */ + + }, { + key: 'get', + value: function (objectId, options) { + this.equalTo('objectId', objectId); + + var firstOptions = {}; + if (options && options.hasOwnProperty('useMasterKey')) { + firstOptions.useMasterKey = options.useMasterKey; + } + if (options && options.hasOwnProperty('sessionToken')) { + firstOptions.sessionToken = options.sessionToken; + } + + return this.first(firstOptions).then(function (response) { + if (response) { + return response; + } + + var errorObject = new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'Object not found.'); + return _ParsePromise2.default.error(errorObject); + })._thenRunCallbacks(options, null); + } + + /** + * Retrieves a list of ParseObjects that satisfy this query. + * Either options.success or options.error is called when the find + * completes. + * + * @method find + * @param {Object} options A Backbone-style options object. Valid options + * are:
    + *
  • success: Function to call when the find completes successfully. + *
  • error: Function to call when the find fails. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * + * @return {Parse.Promise} A promise that is resolved with the results when + * the query completes. + */ + + }, { + key: 'find', + value: function (options) { + var _this2 = this; + + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var select = this._select; + + return controller.find(this.className, this.toJSON(), findOptions).then(function (response) { + return response.results.map(function (data) { + // In cases of relations, the server may send back a className + // on the top level of the payload + var override = response.className || _this2.className; + if (!data.className) { + data.className = override; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(data, select); + } + + return _ParseObject2.default.fromJSON(data, !select); + }); + })._thenRunCallbacks(options); + } + + /** + * Counts the number of objects that match this query. + * Either options.success or options.error is called when the count + * completes. + * + * @method count + * @param {Object} options A Backbone-style options object. Valid options + * are:
    + *
  • success: Function to call when the count completes successfully. + *
  • error: Function to call when the find fails. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * + * @return {Parse.Promise} A promise that is resolved with the count when + * the query completes. + */ + + }, { + key: 'count', + value: function (options) { + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var params = this.toJSON(); + params.limit = 0; + params.count = 1; + + return controller.find(this.className, params, findOptions).then(function (result) { + return result.count; + })._thenRunCallbacks(options); + } + + /** + * Retrieves at most one Parse.Object that satisfies this query. + * + * Either options.success or options.error is called when it completes. + * success is passed the object if there is one. otherwise, undefined. + * + * @method first + * @param {Object} options A Backbone-style options object. Valid options + * are:
    + *
  • success: Function to call when the find completes successfully. + *
  • error: Function to call when the find fails. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * + * @return {Parse.Promise} A promise that is resolved with the object when + * the query completes. + */ + + }, { + key: 'first', + value: function (options) { + var _this3 = this; + + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var params = this.toJSON(); + params.limit = 1; + + var select = this._select; + + return controller.find(this.className, params, findOptions).then(function (response) { + var objects = response.results; + if (!objects[0]) { + return undefined; + } + if (!objects[0].className) { + objects[0].className = _this3.className; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(objects[0], select); + } + + return _ParseObject2.default.fromJSON(objects[0], !select); + })._thenRunCallbacks(options); + } + + /** + * Iterates over each result of a query, calling a callback for each one. If + * the callback returns a promise, the iteration will not continue until + * that promise has been fulfilled. If the callback returns a rejected + * promise, then iteration will stop with that error. The items are + * processed in an unspecified order. The query may not have any sort order, + * and may not use limit or skip. + * @method each + * @param {Function} callback Callback that will be called with each result + * of the query. + * @param {Object} options A Backbone-style options object. Valid options + * are:
    + *
  • success: Function to call when the iteration completes successfully. + *
  • error: Function to call when the iteration fails. + *
  • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
  • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
+ * @return {Parse.Promise} A promise that will be fulfilled once the + * iteration has completed. + */ + + }, { + key: 'each', + value: function (callback, options) { + options = options || {}; + + if (this._order || this._skip || this._limit >= 0) { + return _ParsePromise2.default.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); + } + + new _ParsePromise2.default(); + + + var query = new ParseQuery(this.className); + // We can override the batch size from the options. + // This is undocumented, but useful for testing. + query._limit = options.batchSize || 100; + query._include = this._include.map(function (i) { + return i; + }); + if (this._select) { + query._select = this._select.map(function (s) { + return s; + }); + } + + query._where = {}; + for (var attr in this._where) { + var val = this._where[attr]; + if (Array.isArray(val)) { + query._where[attr] = val.map(function (v) { + return v; + }); + } else if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object') { + var conditionMap = {}; + query._where[attr] = conditionMap; + for (var cond in val) { + conditionMap[cond] = val[cond]; + } + } else { + query._where[attr] = val; + } + } + + query.ascending('objectId'); + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var finished = false; + return _ParsePromise2.default._continueWhile(function () { + return !finished; + }, function () { + return query.find(findOptions).then(function (results) { + var callbacksDone = _ParsePromise2.default.as(); + results.forEach(function (result) { + callbacksDone = callbacksDone.then(function () { + return callback(result); + }); + }); + + return callbacksDone.then(function () { + if (results.length >= query._limit) { + query.greaterThan('objectId', results[results.length - 1].id); + } else { + finished = true; + } + }); + }); + })._thenRunCallbacks(options); + } + + /** Query Conditions **/ + + /** + * Adds a constraint to the query that requires a particular key's value to + * be equal to the provided value. + * @method equalTo + * @param {String} key The key to check. + * @param value The value that the Parse.Object must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'equalTo', + value: function (key, value) { + if (typeof value === 'undefined') { + return this.doesNotExist(key); + } + + this._where[key] = (0, _encode2.default)(value, false, true); + return this; + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be not equal to the provided value. + * @method notEqualTo + * @param {String} key The key to check. + * @param value The value that must not be equalled. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'notEqualTo', + value: function (key, value) { + return this._addCondition(key, '$ne', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than the provided value. + * @method lessThan + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'lessThan', + value: function (key, value) { + return this._addCondition(key, '$lt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than the provided value. + * @method greaterThan + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'greaterThan', + value: function (key, value) { + return this._addCondition(key, '$gt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than or equal to the provided value. + * @method lessThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'lessThanOrEqualTo', + value: function (key, value) { + return this._addCondition(key, '$lte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than or equal to the provided value. + * @method greaterThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'greaterThanOrEqualTo', + value: function (key, value) { + return this._addCondition(key, '$gte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be contained in the provided list of values. + * @method containedIn + * @param {String} key The key to check. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containedIn', + value: function (key, value) { + return this._addCondition(key, '$in', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * not be contained in the provided list of values. + * @method notContainedIn + * @param {String} key The key to check. + * @param {Array} values The values that will not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'notContainedIn', + value: function (key, value) { + return this._addCondition(key, '$nin', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values. + * @method containsAll + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containsAll', + value: function (key, values) { + return this._addCondition(key, '$all', values); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values starting with given strings. + * @method containsAllStartingWith + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The string values that will match as starting string. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containsAllStartingWith', + value: function (key, values) { + var _this = this; + if (!Array.isArray(values)) { + values = [values]; + } + + values = values.map(function (value) { + return { "$regex": _this._regexStartWith(value) }; + }); + + return this.containsAll(key, values); + } + + /** + * Adds a constraint for finding objects that contain the given key. + * @method exists + * @param {String} key The key that should exist. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'exists', + value: function (key) { + return this._addCondition(key, '$exists', true); + } + + /** + * Adds a constraint for finding objects that do not contain a given key. + * @method doesNotExist + * @param {String} key The key that should not exist + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotExist', + value: function (key) { + return this._addCondition(key, '$exists', false); + } + + /** + * Adds a regular expression constraint for finding string values that match + * the provided regular expression. + * This may be slow for large datasets. + * @method matches + * @param {String} key The key that the string to match is stored in. + * @param {RegExp} regex The regular expression pattern to match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matches', + value: function (key, regex, modifiers) { + this._addCondition(key, '$regex', regex); + if (!modifiers) { + modifiers = ''; + } + if (regex.ignoreCase) { + modifiers += 'i'; + } + if (regex.multiline) { + modifiers += 'm'; + } + if (modifiers.length) { + this._addCondition(key, '$options', modifiers); + } + return this; + } + + /** + * Adds a constraint that requires that a key's value matches a Parse.Query + * constraint. + * @method matchesQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matchesQuery', + value: function (key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$inQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value not matches a + * Parse.Query constraint. + * @method doesNotMatchQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotMatchQuery', + value: function (key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$notInQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value matches a value in + * an object returned by a different Parse.Query. + * @method matchesKeyInQuery + * @param {String} key The key that contains the value that is being + * matched. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matchesKeyInQuery', + value: function (key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$select', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint that requires that a key's value not match a value in + * an object returned by a different Parse.Query. + * @method doesNotMatchKeyInQuery + * @param {String} key The key that contains the value that is being + * excluded. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotMatchKeyInQuery', + value: function (key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$dontSelect', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint for finding string values that contain a provided + * string. This may be slow for large datasets. + * @method contains + * @param {String} key The key that the string to match is stored in. + * @param {String} substring The substring that the value must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'contains', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value)); + } + + /** + * Adds a constraint for finding string values that start with a provided + * string. This query will use the backend index, so it will be fast even + * for large datasets. + * @method startsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} prefix The substring that the value must start with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'startsWith', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', this._regexStartWith(value)); + } + + /** + * Adds a constraint for finding string values that end with a provided + * string. This will be slow for large datasets. + * @method endsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} suffix The substring that the value must end with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'endsWith', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value) + '$'); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given. + * @method near + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'near', + value: function (key, point) { + if (!(point instanceof _ParseGeoPoint2.default)) { + // Try to cast it as a GeoPoint + point = new _ParseGeoPoint2.default(point); + } + return this._addCondition(key, '$nearSphere', point); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * @method withinRadians + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in radians) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinRadians', + value: function (key, point, distance) { + this.near(key, point); + return this._addCondition(key, '$maxDistance', distance); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 3958.8 miles. + * @method withinMiles + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in miles) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinMiles', + value: function (key, point, distance) { + return this.withinRadians(key, point, distance / 3958.8); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 6371.0 kilometers. + * @method withinKilometers + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in kilometers) of results + * to return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinKilometers', + value: function (key, point, distance) { + return this.withinRadians(key, point, distance / 6371.0); + } + + /** + * Adds a constraint to the query that requires a particular key's + * coordinates be contained within a given rectangular geographic bounding + * box. + * @method withinGeoBox + * @param {String} key The key to be constrained. + * @param {Parse.GeoPoint} southwest + * The lower-left inclusive corner of the box. + * @param {Parse.GeoPoint} northeast + * The upper-right inclusive corner of the box. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinGeoBox', + value: function (key, southwest, northeast) { + if (!(southwest instanceof _ParseGeoPoint2.default)) { + southwest = new _ParseGeoPoint2.default(southwest); + } + if (!(northeast instanceof _ParseGeoPoint2.default)) { + northeast = new _ParseGeoPoint2.default(northeast); + } + this._addCondition(key, '$within', { '$box': [southwest, northeast] }); + return this; + } + + /** Query Orderings **/ + + /** + * Sorts the results in ascending order by the given key. + * + * @method ascending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'ascending', + value: function () { + this._order = []; + + for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) { + keys[_key] = arguments[_key]; + } + + return this.addAscending.apply(this, keys); + } + + /** + * Sorts the results in ascending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addAscending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'addAscending', + value: function () { + var _this4 = this; + + if (!this._order) { + this._order = []; + } + + for (var _len2 = arguments.length, keys = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + keys[_key2] = arguments[_key2]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + key = key.join(); + } + _this4._order = _this4._order.concat(key.replace(/\s/g, '').split(',')); + }); + + return this; + } + + /** + * Sorts the results in descending order by the given key. + * + * @method descending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'descending', + value: function () { + this._order = []; + + for (var _len3 = arguments.length, keys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + keys[_key3] = arguments[_key3]; + } + + return this.addDescending.apply(this, keys); + } + + /** + * Sorts the results in descending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addDescending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'addDescending', + value: function () { + var _this5 = this; + + if (!this._order) { + this._order = []; + } + + for (var _len4 = arguments.length, keys = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + keys[_key4] = arguments[_key4]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + key = key.join(); + } + _this5._order = _this5._order.concat(key.replace(/\s/g, '').split(',').map(function (k) { + return '-' + k; + })); + }); + + return this; + } + + /** Query Options **/ + + /** + * Sets the number of results to skip before returning any results. + * This is useful for pagination. + * Default is to skip zero results. + * @method skip + * @param {Number} n the number of results to skip. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'skip', + value: function (n) { + if (typeof n !== 'number' || n < 0) { + throw new Error('You can only skip by a positive number'); + } + this._skip = n; + return this; + } + + /** + * Sets the limit of the number of results to return. The default limit is + * 100, with a maximum of 1000 results being returned at a time. + * @method limit + * @param {Number} n the number of results to limit to. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'limit', + value: function (n) { + if (typeof n !== 'number') { + throw new Error('You can only set the limit to a numeric value'); + } + this._limit = n; + return this; + } + + /** + * Includes nested Parse.Objects for the provided key. You can use dot + * notation to specify which fields in the included object are also fetched. + * @method include + * @param {String} key The name of the key to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'include', + value: function () { + var _this6 = this; + + for (var _len5 = arguments.length, keys = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + keys[_key5] = arguments[_key5]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + _this6._include = _this6._include.concat(key); + } else { + _this6._include.push(key); + } + }); + return this; + } + + /** + * Restricts the fields of the returned Parse.Objects to include only the + * provided keys. If this is called multiple times, then all of the keys + * specified in each of the calls will be included. + * @method select + * @param {Array} keys The names of the keys to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'select', + value: function () { + var _this7 = this; + + if (!this._select) { + this._select = []; + } + + for (var _len6 = arguments.length, keys = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + keys[_key6] = arguments[_key6]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + _this7._select = _this7._select.concat(key); + } else { + _this7._select.push(key); + } + }); + return this; + } + + /** + * Subscribe this query to get liveQuery updates + * @method subscribe + * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter + * which can be used to get liveQuery updates. + */ + + }, { + key: 'subscribe', + value: function () { + var controller = _CoreManager2.default.getLiveQueryController(); + return controller.subscribe(this); + } + + /** + * Constructs a Parse.Query that is the OR of the passed in queries. For + * example: + *
var compoundQuery = Parse.Query.or(query1, query2, query3);
+ * + * will create a compoundQuery that is an or of the query1, query2, and + * query3. + * @method or + * @param {...Parse.Query} var_args The list of queries to OR. + * @static + * @return {Parse.Query} The query that is the OR of the passed in queries. + */ + + }], [{ + key: 'or', + value: function () { + var className = null; + + for (var _len7 = arguments.length, queries = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + queries[_key7] = arguments[_key7]; + } + + queries.forEach(function (q) { + if (!className) { + className = q.className; + } + + if (className !== q.className) { + throw new Error('All queries must be for the same class.'); + } + }); + + var query = new ParseQuery(className); + query._orQuery(queries); + return query; + } + }]); + return ParseQuery; +}(); + +exports.default = ParseQuery; + +var DefaultController = { + find: function (className, params, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + return RESTController.request('GET', 'classes/' + className, params, options); + } +}; + +_CoreManager2.default.setQueryController(DefaultController); +},{"./CoreManager":3,"./ParseError":13,"./ParseGeoPoint":15,"./ParseObject":18,"./ParsePromise":20,"./encode":36,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],22:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParseOp = _dereq_('./ParseOp'); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseQuery = _dereq_('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new Relation for the given parent object and key. This + * constructor should rarely be used directly, but rather created by + * Parse.Object.relation. + * @class Parse.Relation + * @constructor + * @param {Parse.Object} parent The parent of this relation. + * @param {String} key The key for this relation on the parent. + * + *

+ * A class that is used to access all of the children of a many-to-many + * relationship. Each instance of Parse.Relation is associated with a + * particular parent object and key. + *

+ */ +var ParseRelation = function () { + function ParseRelation(parent, key) { + (0, _classCallCheck3.default)(this, ParseRelation); + + this.parent = parent; + this.key = key; + this.targetClassName = null; + } + + /** + * Makes sure that this relation has the right parent and key. + */ + + (0, _createClass3.default)(ParseRelation, [{ + key: '_ensureParentAndKey', + value: function (parent, key) { + this.key = this.key || key; + if (this.key !== key) { + throw new Error('Internal Error. Relation retrieved from two different keys.'); + } + if (this.parent) { + if (this.parent.className !== parent.className) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + if (this.parent.id) { + if (this.parent.id !== parent.id) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + } else if (parent.id) { + this.parent = parent; + } + } else { + this.parent = parent; + } + } + + /** + * Adds a Parse.Object or an array of Parse.Objects to the relation. + * @method add + * @param {} objects The item or items to add. + */ + + }, { + key: 'add', + value: function (objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new _ParseOp.RelationOp(objects, []); + var parent = this.parent; + if (!parent) { + throw new Error('Cannot add to a Relation without a parent'); + } + parent.set(this.key, change); + this.targetClassName = change._targetClassName; + return parent; + } + + /** + * Removes a Parse.Object or an array of Parse.Objects from this relation. + * @method remove + * @param {} objects The item or items to remove. + */ + + }, { + key: 'remove', + value: function (objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new _ParseOp.RelationOp([], objects); + if (!this.parent) { + throw new Error('Cannot remove from a Relation without a parent'); + } + this.parent.set(this.key, change); + this.targetClassName = change._targetClassName; + } + + /** + * Returns a JSON version of the object suitable for saving to disk. + * @method toJSON + * @return {Object} + */ + + }, { + key: 'toJSON', + value: function () { + return { + __type: 'Relation', + className: this.targetClassName + }; + } + + /** + * Returns a Parse.Query that is limited to objects in this + * relation. + * @method query + * @return {Parse.Query} + */ + + }, { + key: 'query', + value: function () { + var query; + var parent = this.parent; + if (!parent) { + throw new Error('Cannot construct a query for a Relation without a parent'); + } + if (!this.targetClassName) { + query = new _ParseQuery2.default(parent.className); + query._extraOptions.redirectClassNameForKey = this.key; + } else { + query = new _ParseQuery2.default(this.targetClassName); + } + query._addCondition('$relatedTo', 'object', { + __type: 'Pointer', + className: parent.className, + objectId: parent.id + }); + query._addCondition('$relatedTo', 'key', this.key); + + return query; + } + }]); + return ParseRelation; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseRelation; +},{"./ParseObject":18,"./ParseOp":19,"./ParseQuery":21,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],23:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _get2 = _dereq_('babel-runtime/helpers/get'); + +var _get3 = _interopRequireDefault(_get2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _ParseACL = _dereq_('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseObject2 = _dereq_('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Represents a Role on the Parse server. Roles represent groupings of + * Users for the purposes of granting permissions (e.g. specifying an ACL + * for an Object). Roles are specified by their sets of child users and + * child roles, all of which are granted any permissions that the parent + * role has. + * + *

Roles must have a name (which cannot be changed after creation of the + * role), and must specify an ACL.

+ * @class Parse.Role + * @constructor + * @param {String} name The name of the Role to create. + * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. + * A Parse.Role is a local representation of a role persisted to the Parse + * cloud. + */ +var ParseRole = function (_ParseObject) { + (0, _inherits3.default)(ParseRole, _ParseObject); + + function ParseRole(name, acl) { + (0, _classCallCheck3.default)(this, ParseRole); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseRole.__proto__ || (0, _getPrototypeOf2.default)(ParseRole)).call(this, '_Role')); + + if (typeof name === 'string' && acl instanceof _ParseACL2.default) { + _this.setName(name); + _this.setACL(acl); + } + return _this; + } + + /** + * Gets the name of the role. You can alternatively call role.get("name") + * + * @method getName + * @return {String} the name of the role. + */ + + (0, _createClass3.default)(ParseRole, [{ + key: 'getName', + value: function () { + var name = this.get('name'); + if (name == null || typeof name === 'string') { + return name; + } + return ''; + } + + /** + * Sets the name for a role. This value must be set before the role has + * been saved to the server, and cannot be set once the role has been + * saved. + * + *

+ * A role's name can only contain alphanumeric characters, _, -, and + * spaces. + *

+ * + *

This is equivalent to calling role.set("name", name)

+ * + * @method setName + * @param {String} name The name of the role. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + + }, { + key: 'setName', + value: function (name, options) { + return this.set('name', name, options); + } + + /** + * Gets the Parse.Relation for the Parse.Users that are direct + * children of this role. These users are granted any privileges that this + * role has been granted (e.g. read or write access through ACLs). You can + * add or remove users from the role through this relation. + * + *

This is equivalent to calling role.relation("users")

+ * + * @method getUsers + * @return {Parse.Relation} the relation for the users belonging to this + * role. + */ + + }, { + key: 'getUsers', + value: function () { + return this.relation('users'); + } + + /** + * Gets the Parse.Relation for the Parse.Roles that are direct + * children of this role. These roles' users are granted any privileges that + * this role has been granted (e.g. read or write access through ACLs). You + * can add or remove child roles from this role through this relation. + * + *

This is equivalent to calling role.relation("roles")

+ * + * @method getRoles + * @return {Parse.Relation} the relation for the roles belonging to this + * role. + */ + + }, { + key: 'getRoles', + value: function () { + return this.relation('roles'); + } + }, { + key: 'validate', + value: function (attrs, options) { + var isInvalid = (0, _get3.default)(ParseRole.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseRole.prototype), 'validate', this).call(this, attrs, options); + if (isInvalid) { + return isInvalid; + } + + if ('name' in attrs && attrs.name !== this.getName()) { + var newName = attrs.name; + if (this.id && this.id !== attrs.objectId) { + // Check to see if the objectId being set matches this.id + // This happens during a fetch -- the id is set before calling fetch + // Let the name be set in this case + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); + } + if (typeof newName !== 'string') { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name must be a String.'); + } + if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); + } + } + return false; + } + }]); + return ParseRole; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseRole; + +_ParseObject3.default.registerSubclass('_Role', ParseRole); +},{"./ParseACL":11,"./ParseError":13,"./ParseObject":18,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/get":58,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],24:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _isRevocableSession = _dereq_('./isRevocableSession'); + +var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); + +var _ParseObject2 = _dereq_('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseUser = _dereq_('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * @class Parse.Session + * @constructor + * + *

A Parse.Session object is a local representation of a revocable session. + * This class is a subclass of a Parse.Object, and retains the same + * functionality of a Parse.Object.

+ */ +var ParseSession = function (_ParseObject) { + (0, _inherits3.default)(ParseSession, _ParseObject); + + function ParseSession(attributes) { + (0, _classCallCheck3.default)(this, ParseSession); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseSession.__proto__ || (0, _getPrototypeOf2.default)(ParseSession)).call(this, '_Session')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + return _this; + } + + /** + * Returns the session token string. + * @method getSessionToken + * @return {String} + */ + + (0, _createClass3.default)(ParseSession, [{ + key: 'getSessionToken', + value: function () { + var token = this.get('sessionToken'); + if (typeof token === 'string') { + return token; + } + return ''; + } + }], [{ + key: 'readOnlyAttributes', + value: function () { + return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; + } + + /** + * Retrieves the Session object for the currently logged in session. + * @method current + * @static + * @return {Parse.Promise} A promise that is resolved with the Parse.Session + * object after it has been fetched. If there is no current user, the + * promise will be rejected. + */ + + }, { + key: 'current', + value: function (options) { + options = options || {}; + var controller = _CoreManager2.default.getSessionController(); + + var sessionOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + sessionOptions.useMasterKey = options.useMasterKey; + } + return _ParseUser2.default.currentAsync().then(function (user) { + if (!user) { + return _ParsePromise2.default.error('There is no current user.'); + } + user.getSessionToken(); + + sessionOptions.sessionToken = user.getSessionToken(); + return controller.getSession(sessionOptions); + }); + } + + /** + * Determines whether the current session token is revocable. + * This method is useful for migrating Express.js or Node.js web apps to + * use revocable sessions. If you are migrating an app that uses the Parse + * SDK in the browser only, please use Parse.User.enableRevocableSession() + * instead, so that sessions can be automatically upgraded. + * @method isCurrentSessionRevocable + * @static + * @return {Boolean} + */ + + }, { + key: 'isCurrentSessionRevocable', + value: function () { + var currentUser = _ParseUser2.default.current(); + if (currentUser) { + return (0, _isRevocableSession2.default)(currentUser.getSessionToken() || ''); + } + return false; + } + }]); + return ParseSession; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseSession; + +_ParseObject3.default.registerSubclass('_Session', ParseSession); + +var DefaultController = { + getSession: function (options) { + var RESTController = _CoreManager2.default.getRESTController(); + var session = new ParseSession(); + + return RESTController.request('GET', 'sessions/me', {}, options).then(function (sessionData) { + session._finishFetch(sessionData); + session._setExisted(true); + return session; + }); + } +}; + +_CoreManager2.default.setSessionController(DefaultController); +},{"./CoreManager":3,"./ParseObject":18,"./ParsePromise":20,"./ParseUser":25,"./isRevocableSession":39,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],25:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _defineProperty = _dereq_('babel-runtime/core-js/object/define-property'); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _get2 = _dereq_('babel-runtime/helpers/get'); + +var _get3 = _interopRequireDefault(_get2); + +var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _isRevocableSession = _dereq_('./isRevocableSession'); + +var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseObject2 = _dereq_('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseSession = _dereq_('./ParseSession'); + +var _ParseSession2 = _interopRequireDefault(_ParseSession); + +var _Storage = _dereq_('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var CURRENT_USER_KEY = 'currentUser'; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var canUseCurrentUser = !_CoreManager2.default.get('IS_NODE'); +var currentUserCacheMatchesDisk = false; +var currentUserCache = null; + +var authProviders = {}; + +/** + * @class Parse.User + * @constructor + * + *

A Parse.User object is a local representation of a user persisted to the + * Parse cloud. This class is a subclass of a Parse.Object, and retains the + * same functionality of a Parse.Object, but also extends it with various + * user specific methods, like authentication, signing up, and validation of + * uniqueness.

+ */ + +var ParseUser = function (_ParseObject) { + (0, _inherits3.default)(ParseUser, _ParseObject); + + function ParseUser(attributes) { + (0, _classCallCheck3.default)(this, ParseUser); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseUser.__proto__ || (0, _getPrototypeOf2.default)(ParseUser)).call(this, '_User')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Parse User'); + } + } + return _this; + } + + /** + * Request a revocable session token to replace the older style of token. + * @method _upgradeToRevocableSession + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is resolved when the replacement + * token has been fetched. + */ + + (0, _createClass3.default)(ParseUser, [{ + key: '_upgradeToRevocableSession', + value: function (options) { + options = options || {}; + + var upgradeOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + upgradeOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); + } + + /** + * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can + * call linkWith on the user (even if it doesn't exist yet on the server). + * @method _linkWith + */ + + }, { + key: '_linkWith', + value: function (provider, options) { + var _this2 = this; + + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[provider]; + } else { + authType = provider.getAuthType(); + } + if (options && options.hasOwnProperty('authData')) { + var authData = this.get('authData') || {}; + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + throw new Error('Invalid type: authData field should be an object'); + } + authData[authType] = options.authData; + + var controller = _CoreManager2.default.getUserController(); + return controller.linkWith(this, authData)._thenRunCallbacks(options, this); + } else { + var promise = new _ParsePromise2.default(); + provider.authenticate({ + success: function (provider, result) { + var opts = {}; + opts.authData = result; + if (options.success) { + opts.success = options.success; + } + if (options.error) { + opts.error = options.error; + } + _this2._linkWith(provider, opts).then(function () { + promise.resolve(_this2); + }, function (error) { + promise.reject(error); + }); + }, + error: function (provider, _error) { + if (typeof options.error === 'function') { + options.error(_this2, _error); + } + promise.reject(_error); + } + }); + return promise; + } + } + + /** + * Synchronizes auth data for a provider (e.g. puts the access token in the + * right place to be used by the Facebook SDK). + * @method _synchronizeAuthData + */ + + }, { + key: '_synchronizeAuthData', + value: function (provider) { + if (!this.isCurrent() || !provider) { + return; + } + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[authType]; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData'); + if (!provider || !authData || (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + var success = provider.restoreAuthentication(authData[authType]); + if (!success) { + this._unlinkFrom(provider); + } + } + + /** + * Synchronizes authData for all providers. + * @method _synchronizeAllAuthData + */ + + }, { + key: '_synchronizeAllAuthData', + value: function () { + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + this._synchronizeAuthData(key); + } + } + + /** + * Removes null values from authData (which exist temporarily for + * unlinking) + * @method _cleanupAuthData + */ + + }, { + key: '_cleanupAuthData', + value: function () { + if (!this.isCurrent()) { + return; + } + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + if (!authData[key]) { + delete authData[key]; + } + } + } + + /** + * Unlinks a user from a service. + * @method _unlinkFrom + */ + + }, { + key: '_unlinkFrom', + value: function (provider, options) { + var _this3 = this; + + if (typeof provider === 'string') { + provider = authProviders[provider]; + } else { + provider.getAuthType(); + } + return this._linkWith(provider, { authData: null }).then(function () { + _this3._synchronizeAuthData(provider); + return _ParsePromise2.default.as(_this3); + })._thenRunCallbacks(options); + } + + /** + * Checks whether a user is linked to a service. + * @method _isLinked + */ + + }, { + key: '_isLinked', + value: function (provider) { + var authType; + if (typeof provider === 'string') { + authType = provider; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData') || {}; + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return false; + } + return !!authData[authType]; + } + + /** + * Deauthenticates all providers. + * @method _logOutWithAll + */ + + }, { + key: '_logOutWithAll', + value: function () { + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + this._logOutWith(key); + } + } + + /** + * Deauthenticates a single provider (e.g. removing access tokens from the + * Facebook SDK). + * @method _logOutWith + */ + + }, { + key: '_logOutWith', + value: function (provider) { + if (!this.isCurrent()) { + return; + } + if (typeof provider === 'string') { + provider = authProviders[provider]; + } + if (provider && provider.deauthenticate) { + provider.deauthenticate(); + } + } + + /** + * Class instance method used to maintain specific keys when a fetch occurs. + * Used to ensure that the session token is not lost. + */ + + }, { + key: '_preserveFieldsOnFetch', + value: function () { + return { + sessionToken: this.get('sessionToken') + }; + } + + /** + * Returns true if current would return this user. + * @method isCurrent + * @return {Boolean} + */ + + }, { + key: 'isCurrent', + value: function () { + var current = ParseUser.current(); + return !!current && current.id === this.id; + } + + /** + * Returns get("username"). + * @method getUsername + * @return {String} + */ + + }, { + key: 'getUsername', + value: function () { + var username = this.get('username'); + if (username == null || typeof username === 'string') { + return username; + } + return ''; + } + + /** + * Calls set("username", username, options) and returns the result. + * @method setUsername + * @param {String} username + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setUsername', + value: function (username) { + // Strip anonymity, even we do not support anonymous user in js SDK, we may + // encounter anonymous user created by android/iOS in cloud code. + var authData = this.get('authData'); + if (authData && (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) === 'object' && authData.hasOwnProperty('anonymous')) { + // We need to set anonymous to null instead of deleting it in order to remove it from Parse. + authData.anonymous = null; + } + this.set('username', username); + } + + /** + * Calls set("password", password, options) and returns the result. + * @method setPassword + * @param {String} password + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setPassword', + value: function (password) { + this.set('password', password); + } + + /** + * Returns get("email"). + * @method getEmail + * @return {String} + */ + + }, { + key: 'getEmail', + value: function () { + var email = this.get('email'); + if (email == null || typeof email === 'string') { + return email; + } + return ''; + } + + /** + * Calls set("email", email, options) and returns the result. + * @method setEmail + * @param {String} email + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setEmail', + value: function (email) { + this.set('email', email); + } + + /** + * Returns the session token for this user, if the user has been logged in, + * or if it is the result of a query with the master key. Otherwise, returns + * undefined. + * @method getSessionToken + * @return {String} the session token, or undefined + */ + + }, { + key: 'getSessionToken', + value: function () { + var token = this.get('sessionToken'); + if (token == null || typeof token === 'string') { + return token; + } + return ''; + } + + /** + * Checks whether this user is the current user and has been authenticated. + * @method authenticated + * @return (Boolean) whether this user is the current user and is logged in. + */ + + }, { + key: 'authenticated', + value: function () { + var current = ParseUser.current(); + return !!this.get('sessionToken') && !!current && current.id === this.id; + } + + /** + * Signs up a new user. You should call this instead of save for + * new Parse.Users. This will create a new Parse.User on the server, and + * also persist the session on disk so that you can access the user using + * current. + * + *

A username and password must be set before calling signUp.

+ * + *

Calls options.success or options.error on completion.

+ * + * @method signUp + * @param {Object} attrs Extra fields to set on the new user, or null. + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled when the signup + * finishes. + */ + + }, { + key: 'signUp', + value: function (attrs, options) { + options = options || {}; + + var signupOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + signupOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + signupOptions.installationId = options.installationId; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); + } + + /** + * Logs in a Parse.User. On success, this saves the session to disk, + * so you can retrieve the currently logged in user using + * current. + * + *

A username and password must be set before calling logIn.

+ * + *

Calls options.success or options.error on completion.

+ * + * @method logIn + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login is complete. + */ + + }, { + key: 'logIn', + value: function (options) { + options = options || {}; + + var loginOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + loginOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + loginOptions.installationId = options.installationId; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); + } + + /** + * Wrap the default save behavior with functionality to save to local + * storage if this is current user. + */ + + }, { + key: 'save', + value: function () { + var _this4 = this; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'save', this).apply(this, args).then(function () { + if (_this4.isCurrent()) { + return _CoreManager2.default.getUserController().updateUserOnDisk(_this4); + } + return _this4; + }); + } + + /** + * Wrap the default destroy behavior with functionality that logs out + * the current user when it is destroyed + */ + + }, { + key: 'destroy', + value: function () { + var _this5 = this; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'destroy', this).apply(this, args).then(function () { + if (_this5.isCurrent()) { + return _CoreManager2.default.getUserController().removeUserFromDisk(); + } + return _this5; + }); + } + + /** + * Wrap the default fetch behavior with functionality to save to local + * storage if this is current user. + */ + + }, { + key: 'fetch', + value: function () { + var _this6 = this; + + for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'fetch', this).apply(this, args).then(function () { + if (_this6.isCurrent()) { + return _CoreManager2.default.getUserController().updateUserOnDisk(_this6); + } + return _this6; + }); + } + }], [{ + key: 'readOnlyAttributes', + value: function () { + return ['sessionToken']; + } + + /** + * Adds functionality to the existing Parse.User class + * @method extend + * @param {Object} protoProps A set of properties to add to the prototype + * @param {Object} classProps A set of static properties to add to the class + * @static + * @return {Class} The newly extended Parse.User class + */ + + }, { + key: 'extend', + value: function (protoProps, classProps) { + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseUser.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseUser, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + return ParseUser; + } + + /** + * Retrieves the currently logged in ParseUser with a valid session, + * either from memory or localStorage, if necessary. + * @method current + * @static + * @return {Parse.Object} The currently logged in Parse.User. + */ + + }, { + key: 'current', + value: function () { + if (!canUseCurrentUser) { + return null; + } + var controller = _CoreManager2.default.getUserController(); + return controller.currentUser(); + } + + /** + * Retrieves the currently logged in ParseUser from asynchronous Storage. + * @method currentAsync + * @static + * @return {Parse.Promise} A Promise that is resolved with the currently + * logged in Parse User + */ + + }, { + key: 'currentAsync', + value: function () { + if (!canUseCurrentUser) { + return _ParsePromise2.default.as(null); + } + var controller = _CoreManager2.default.getUserController(); + return controller.currentUserAsync(); + } + + /** + * Signs up a new user with a username (or email) and password. + * This will create a new Parse.User on the server, and also persist the + * session in localStorage so that you can access the user using + * {@link #current}. + * + *

Calls options.success or options.error on completion.

+ * + * @method signUp + * @param {String} username The username (or email) to sign up with. + * @param {String} password The password to sign up with. + * @param {Object} attrs Extra fields to set on the new user. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the signup completes. + */ + + }, { + key: 'signUp', + value: function (username, password, attrs, options) { + attrs = attrs || {}; + attrs.username = username; + attrs.password = password; + var user = new ParseUser(attrs); + return user.signUp({}, options); + } + + /** + * Logs in a user with a username (or email) and password. On success, this + * saves the session to disk, so you can retrieve the currently logged in + * user using current. + * + *

Calls options.success or options.error on completion.

+ * + * @method logIn + * @param {String} username The username (or email) to log in with. + * @param {String} password The password to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + + }, { + key: 'logIn', + value: function (username, password, options) { + if (typeof username !== 'string') { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Username must be a string.')); + } else if (typeof password !== 'string') { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Password must be a string.')); + } + var user = new ParseUser(); + user._finishFetch({ username: username, password: password }); + return user.logIn(options); + } + + /** + * Logs in a user with a session token. On success, this saves the session + * to disk, so you can retrieve the currently logged in user using + * current. + * + *

Calls options.success or options.error on completion.

+ * + * @method become + * @param {String} sessionToken The sessionToken to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + + }, { + key: 'become', + value: function (sessionToken, options) { + if (!canUseCurrentUser) { + throw new Error('It is not memory-safe to become a user in a server environment'); + } + options = options || {}; + + var becomeOptions = { + sessionToken: sessionToken + }; + if (options.hasOwnProperty('useMasterKey')) { + becomeOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.become(becomeOptions)._thenRunCallbacks(options); + } + }, { + key: 'logInWith', + value: function (provider, options) { + return ParseUser._logInWith(provider, options); + } + + /** + * Logs out the currently logged in user session. This will remove the + * session from disk, log out of linked services, and future calls to + * current will return null. + * @method logOut + * @static + * @return {Parse.Promise} A promise that is resolved when the session is + * destroyed on the server. + */ + + }, { + key: 'logOut', + value: function () { + if (!canUseCurrentUser) { + throw new Error('There is no current user user on a node.js server environment.'); + } + + var controller = _CoreManager2.default.getUserController(); + return controller.logOut(); + } + + /** + * Requests a password reset email to be sent to the specified email address + * associated with the user account. This email allows the user to securely + * reset their password on the Parse site. + * + *

Calls options.success or options.error on completion.

+ * + * @method requestPasswordReset + * @param {String} email The email address associated with the user that + * forgot their password. + * @param {Object} options A Backbone-style options object. + * @static + */ + + }, { + key: 'requestPasswordReset', + value: function (email, options) { + options = options || {}; + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); + } + + /** + * Allow someone to define a custom User class without className + * being rewritten to _User. The default behavior is to rewrite + * User to _User for legacy reasons. This allows developers to + * override that behavior. + * + * @method allowCustomUserClass + * @param {Boolean} isAllowed Whether or not to allow custom User class + * @static + */ + + }, { + key: 'allowCustomUserClass', + value: function (isAllowed) { + _CoreManager2.default.set('PERFORM_USER_REWRITE', !isAllowed); + } + + /** + * Allows a legacy application to start using revocable sessions. If the + * current session token is not revocable, a request will be made for a new, + * revocable session. + * It is not necessary to call this method from cloud code unless you are + * handling user signup or login from the server side. In a cloud code call, + * this function will not attempt to upgrade the current token. + * @method enableRevocableSession + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is resolved when the process has + * completed. If a replacement session token is requested, the promise + * will be resolved after a new token has been fetched. + */ + + }, { + key: 'enableRevocableSession', + value: function (options) { + options = options || {}; + _CoreManager2.default.set('FORCE_REVOCABLE_SESSION', true); + if (canUseCurrentUser) { + var current = ParseUser.current(); + if (current) { + return current._upgradeToRevocableSession(options); + } + } + return _ParsePromise2.default.as()._thenRunCallbacks(options); + } + + /** + * Enables the use of become or the current user in a server + * environment. These features are disabled by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method enableUnsafeCurrentUser + * @static + */ + + }, { + key: 'enableUnsafeCurrentUser', + value: function () { + canUseCurrentUser = true; + } + + /** + * Disables the use of become or the current user in any environment. + * These features are disabled on servers by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method disableUnsafeCurrentUser + * @static + */ + + }, { + key: 'disableUnsafeCurrentUser', + value: function () { + canUseCurrentUser = false; + } + }, { + key: '_registerAuthenticationProvider', + value: function (provider) { + authProviders[provider.getAuthType()] = provider; + // Synchronize the current user with the auth provider. + ParseUser.currentAsync().then(function (current) { + if (current) { + current._synchronizeAuthData(provider.getAuthType()); + } + }); + } + }, { + key: '_logInWith', + value: function (provider, options) { + var user = new ParseUser(); + return user._linkWith(provider, options); + } + }, { + key: '_clearCache', + value: function () { + currentUserCache = null; + currentUserCacheMatchesDisk = false; + } + }, { + key: '_setCurrentUserCache', + value: function (user) { + currentUserCache = user; + } + }]); + return ParseUser; +}(_ParseObject3.default); + +exports.default = ParseUser; + +_ParseObject3.default.registerSubclass('_User', ParseUser); + +var DefaultController = { + updateUserOnDisk: function (user) { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var json = user.toJSON(); + json.className = '_User'; + return _Storage2.default.setItemAsync(path, (0, _stringify2.default)(json)).then(function () { + return user; + }); + }, + removeUserFromDisk: function () { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + currentUserCacheMatchesDisk = true; + currentUserCache = null; + return _Storage2.default.removeItemAsync(path); + }, + setCurrentUser: function (user) { + currentUserCache = user; + user._cleanupAuthData(); + user._synchronizeAllAuthData(); + return DefaultController.updateUserOnDisk(user); + }, + currentUser: function () { + if (currentUserCache) { + return currentUserCache; + } + if (currentUserCacheMatchesDisk) { + return null; + } + if (_Storage2.default.async()) { + throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); + } + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var userData = _Storage2.default.getItem(path); + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return null; + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = _ParseObject3.default.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return current; + }, + currentUserAsync: function () { + if (currentUserCache) { + return _ParsePromise2.default.as(currentUserCache); + } + if (currentUserCacheMatchesDisk) { + return _ParsePromise2.default.as(null); + } + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + return _Storage2.default.getItemAsync(path).then(function (userData) { + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return _ParsePromise2.default.as(null); + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = _ParseObject3.default.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return _ParsePromise2.default.as(current); + }); + }, + signUp: function (user, attrs, options) { + var username = attrs && attrs.username || user.get('username'); + var password = attrs && attrs.password || user.get('password'); + + if (!username || !username.length) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); + } + if (!password || !password.length) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); + } + + return user.save(attrs, options).then(function () { + // Clear the password field + user._finishFetch({ password: undefined }); + + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + }, + logIn: function (user, options) { + var RESTController = _CoreManager2.default.getRESTController(); + var stateController = _CoreManager2.default.getObjectStateController(); + var auth = { + username: user.get('username'), + password: user.get('password') + }; + return RESTController.request('GET', 'login', auth, options).then(function (response, status) { + user._migrateId(response.objectId); + user._setExisted(true); + stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); + stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); + response.password = undefined; + user._finishFetch(response); + if (!canUseCurrentUser) { + // We can't set the current user, so just return the one we logged in + return _ParsePromise2.default.as(user); + } + return DefaultController.setCurrentUser(user); + }); + }, + become: function (options) { + var user = new ParseUser(); + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('GET', 'users/me', {}, options).then(function (response, status) { + user._finishFetch(response); + user._setExisted(true); + return DefaultController.setCurrentUser(user); + }); + }, + logOut: function () { + return DefaultController.currentUserAsync().then(function (currentUser) { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var promise = _Storage2.default.removeItemAsync(path); + var RESTController = _CoreManager2.default.getRESTController(); + if (currentUser !== null) { + var currentSession = currentUser.getSessionToken(); + if (currentSession && (0, _isRevocableSession2.default)(currentSession)) { + promise = promise.then(function () { + return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); + }); + } + currentUser._logOutWithAll(); + currentUser._finishFetch({ sessionToken: undefined }); + } + currentUserCacheMatchesDisk = true; + currentUserCache = null; + + return promise; + }); + }, + requestPasswordReset: function (email, options) { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); + }, + upgradeToRevocableSession: function (user, options) { + var token = user.getSessionToken(); + if (!token) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.SESSION_MISSING, 'Cannot upgrade a user with no session token')); + } + + options.sessionToken = token; + + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(function (result) { + var session = new _ParseSession2.default(); + session._finishFetch(result); + user._finishFetch({ sessionToken: session.getSessionToken() }); + if (user.isCurrent()) { + return DefaultController.setCurrentUser(user); + } + return _ParsePromise2.default.as(user); + }); + }, + linkWith: function (user, authData) { + return user.save({ authData: authData }).then(function () { + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + } +}; + +_CoreManager2.default.setUserController(DefaultController); +},{"./CoreManager":3,"./ParseError":13,"./ParseObject":18,"./ParsePromise":20,"./ParseSession":24,"./Storage":29,"./isRevocableSession":39,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/object/define-property":47,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/get":58,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],26:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.send = send; + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParseQuery = _dereq_('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains functions to deal with Push in Parse. + * @class Parse.Push + * @static + */ + +/** + * Sends a push notification. + * @method send + * @param {Object} data - The data of the push notification. Valid fields + * are: + *
    + *
  1. channels - An Array of channels to push to.
  2. + *
  3. push_time - A Date object for when to send the push.
  4. + *
  5. expiration_time - A Date object for when to expire + * the push.
  6. + *
  7. expiration_interval - The seconds from now to expire the push.
  8. + *
  9. where - A Parse.Query over Parse.Installation that is used to match + * a set of installations to push to.
  10. + *
  11. data - The data to send as part of the push
  12. + *
      + * @param {Object} options An object that has an optional success function, + * that takes no arguments and will be called on a successful push, and + * an error function that takes a Parse.Error and will be called if the push + * failed. + * @return {Parse.Promise} A promise that is fulfilled when the push request + * completes. + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function send(data, options) { + options = options || {}; + + if (data.where && data.where instanceof _ParseQuery2.default) { + data.where = data.where.toJSON().where; + } + + if (data.push_time && (0, _typeof3.default)(data.push_time) === 'object') { + data.push_time = data.push_time.toJSON(); + } + + if (data.expiration_time && (0, _typeof3.default)(data.expiration_time) === 'object') { + data.expiration_time = data.expiration_time.toJSON(); + } + + if (data.expiration_time && data.expiration_interval) { + throw new Error('expiration_time and expiration_interval cannot both be set.'); + } + + return _CoreManager2.default.getPushController().send(data, { + useMasterKey: options.useMasterKey + })._thenRunCallbacks(options); +} + +var DefaultController = { + send: function (data, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); + + return request._thenRunCallbacks(options); + } +}; + +_CoreManager2.default.setPushController(DefaultController); +},{"./CoreManager":3,"./ParseQuery":21,"babel-runtime/helpers/typeof":61}],27:[function(_dereq_,module,exports){ +(function (process){ +'use strict'; + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParseError = _dereq_('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = _dereq_('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var XHR = null; +if (typeof XMLHttpRequest !== 'undefined') { + XHR = XMLHttpRequest; +} + + +var useXDomainRequest = false; +if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { + useXDomainRequest = true; +} + +function ajaxIE9(method, url, data) { + var promise = new _ParsePromise2.default(); + var xdr = new XDomainRequest(); + xdr.onload = function () { + var response; + try { + response = JSON.parse(xdr.responseText); + } catch (e) { + promise.reject(e); + } + if (response) { + promise.resolve(response); + } + }; + xdr.onerror = xdr.ontimeout = function () { + // Let's fake a real error message. + var fakeResponse = { + responseText: (0, _stringify2.default)({ + code: _ParseError2.default.X_DOMAIN_REQUEST, + error: 'IE\'s XDomainRequest does not supply error info.' + }) + }; + promise.reject(fakeResponse); + }; + xdr.onprogress = function () {}; + xdr.open(method, url); + xdr.send(data); + return promise; +} + +var RESTController = { + ajax: function (method, url, data, headers) { + if (useXDomainRequest) { + return ajaxIE9(method, url, data, headers); + } + + var promise = new _ParsePromise2.default(); + var attempts = 0; + + (function dispatch() { + if (XHR == null) { + throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); + } + var handled = false; + var xhr = new XHR(); + + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4 || handled) { + return; + } + handled = true; + + if (xhr.status >= 200 && xhr.status < 300) { + var response; + try { + response = JSON.parse(xhr.responseText); + } catch (e) { + promise.reject(e.toString()); + } + if (response) { + promise.resolve(response, xhr.status, xhr); + } + } else if (xhr.status >= 500 || xhr.status === 0) { + // retry on 5XX or node-xmlhttprequest error + if (++attempts < _CoreManager2.default.get('REQUEST_ATTEMPT_LIMIT')) { + // Exponentially-growing random delay + var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); + setTimeout(dispatch, delay); + } else if (xhr.status === 0) { + promise.reject('Unable to connect to the Parse API'); + } else { + // After the retry limit is reached, fail + promise.reject(xhr); + } + } else { + promise.reject(xhr); + } + }; + + headers = headers || {}; + if (typeof headers['Content-Type'] !== 'string') { + headers['Content-Type'] = 'text/plain'; // Avoid pre-flight + } + if (_CoreManager2.default.get('IS_NODE')) { + headers['User-Agent'] = 'Parse/' + _CoreManager2.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; + } + + xhr.open(method, url, true); + for (var h in headers) { + xhr.setRequestHeader(h, headers[h]); + } + xhr.send(data); + })(); + + return promise; + }, + request: function (method, path, data, options) { + options = options || {}; + var url = _CoreManager2.default.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += path; + + var payload = {}; + if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') { + for (var k in data) { + payload[k] = data[k]; + } + } + + if (method !== 'POST') { + payload._method = method; + method = 'POST'; + } + + payload._ApplicationId = _CoreManager2.default.get('APPLICATION_ID'); + var jsKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); + if (jsKey) { + payload._JavaScriptKey = jsKey; + } + payload._ClientVersion = _CoreManager2.default.get('VERSION'); + + var useMasterKey = options.useMasterKey; + if (typeof useMasterKey === 'undefined') { + useMasterKey = _CoreManager2.default.get('USE_MASTER_KEY'); + } + if (useMasterKey) { + if (_CoreManager2.default.get('MASTER_KEY')) { + delete payload._JavaScriptKey; + payload._MasterKey = _CoreManager2.default.get('MASTER_KEY'); + } else { + throw new Error('Cannot use the Master Key, it has not been provided.'); + } + } + + if (_CoreManager2.default.get('FORCE_REVOCABLE_SESSION')) { + payload._RevocableSession = '1'; + } + + var installationId = options.installationId; + var installationIdPromise; + if (installationId && typeof installationId === 'string') { + installationIdPromise = _ParsePromise2.default.as(installationId); + } else { + var installationController = _CoreManager2.default.getInstallationController(); + installationIdPromise = installationController.currentInstallationId(); + } + + return installationIdPromise.then(function (iid) { + payload._InstallationId = iid; + var userController = _CoreManager2.default.getUserController(); + if (options && typeof options.sessionToken === 'string') { + return _ParsePromise2.default.as(options.sessionToken); + } else if (userController) { + return userController.currentUserAsync().then(function (user) { + if (user) { + return _ParsePromise2.default.as(user.getSessionToken()); + } + return _ParsePromise2.default.as(null); + }); + } + return _ParsePromise2.default.as(null); + }).then(function (token) { + if (token) { + payload._SessionToken = token; + } + + var payloadString = (0, _stringify2.default)(payload); + + return RESTController.ajax(method, url, payloadString); + }).then(null, function (response) { + // Transform the error into an instance of ParseError by trying to parse + // the error string as JSON + var error; + if (response && response.responseText) { + try { + var errorJSON = JSON.parse(response.responseText); + error = new _ParseError2.default(errorJSON.code, errorJSON.error); + } catch (e) { + // If we fail to parse the error text, that's okay. + error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); + } + } else { + error = new _ParseError2.default(_ParseError2.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify2.default)(response)); + } + + return _ParsePromise2.default.error(error); + }); + }, + _setXHR: function (xhr) { + XHR = xhr; + } +}; + +module.exports = RESTController; +}).call(this,_dereq_('_process')) +},{"./CoreManager":3,"./ParseError":13,"./ParsePromise":20,"./Storage":29,"_process":168,"babel-runtime/core-js/json/stringify":44,"babel-runtime/helpers/typeof":61}],28:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getState = getState; +exports.initializeState = initializeState; +exports.removeState = removeState; +exports.getServerData = getServerData; +exports.setServerData = setServerData; +exports.getPendingOps = getPendingOps; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.getObjectCache = getObjectCache; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; +exports.enqueueTask = enqueueTask; +exports.clearAllState = clearAllState; +exports.duplicateState = duplicateState; + +var _ObjectStateMutations = _dereq_('./ObjectStateMutations'); + +var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +var objectState = {}; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function getState(obj) { + var classData = objectState[obj.className]; + if (classData) { + return classData[obj.id] || null; + } + return null; +} + +function initializeState(obj, initial) { + var state = getState(obj); + if (state) { + return state; + } + if (!objectState[obj.className]) { + objectState[obj.className] = {}; + } + if (!initial) { + initial = ObjectStateMutations.defaultState(); + } + state = objectState[obj.className][obj.id] = initial; + return state; +} + +function removeState(obj) { + var state = getState(obj); + if (state === null) { + return null; + } + delete objectState[obj.className][obj.id]; + return state; +} + +function getServerData(obj) { + var state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +function setServerData(obj, attributes) { + var serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +function getPendingOps(obj) { + var state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +function setPendingOp(obj, attr, op) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +function pushPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +function popPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +function mergeFirstPendingState(obj) { + var pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +function getObjectCache(obj) { + var state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +function estimateAttribute(obj, attr) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +function estimateAttributes(obj) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +function commitServerChanges(obj, changes) { + var state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +function enqueueTask(obj, task) { + var state = initializeState(obj); + return state.tasks.enqueue(task); +} + +function clearAllState() { + objectState = {}; +} + +function duplicateState(source, dest) { + dest.id = source.id; +} +},{"./ObjectStateMutations":9}],29:[function(_dereq_,module,exports){ +'use strict'; + +var _CoreManager = _dereq_('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = { + async: function () { + var controller = _CoreManager2.default.getStorageController(); + return !!controller.async; + }, + getItem: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.getItem(path); + }, + getItemAsync: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.getItemAsync(path); + } + return _ParsePromise2.default.as(controller.getItem(path)); + }, + setItem: function (path, value) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.setItem(path, value); + }, + setItemAsync: function (path, value) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.setItemAsync(path, value); + } + return _ParsePromise2.default.as(controller.setItem(path, value)); + }, + removeItem: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.removeItem(path); + }, + removeItemAsync: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.removeItemAsync(path); + } + return _ParsePromise2.default.as(controller.removeItem(path)); + }, + generatePath: function (path) { + if (!_CoreManager2.default.get('APPLICATION_ID')) { + throw new Error('You need to call Parse.initialize before using Parse.'); + } + if (typeof path !== 'string') { + throw new Error('Tried to get a Storage path that was not a String.'); + } + if (path[0] === '/') { + path = path.substr(1); + } + return 'Parse/' + _CoreManager2.default.get('APPLICATION_ID') + '/' + path; + }, + _clear: function () { + var controller = _CoreManager2.default.getStorageController(); + if (controller.hasOwnProperty('clear')) { + controller.clear(); + } + } +}; + +_CoreManager2.default.setStorageController(_dereq_('./StorageController.browser')); +},{"./CoreManager":3,"./ParsePromise":20,"./StorageController.browser":30}],30:[function(_dereq_,module,exports){ +'use strict'; + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var StorageController = { + async: 0, + + getItem: function (path) { + return localStorage.getItem(path); + }, + setItem: function (path, value) { + try { + localStorage.setItem(path, value); + } catch (e) { + // Quota exceeded, possibly due to Safari Private Browsing mode + } + }, + removeItem: function (path) { + localStorage.removeItem(path); + }, + clear: function () { + localStorage.clear(); + } +}; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = StorageController; +},{"./ParsePromise":20}],31:[function(_dereq_,module,exports){ +'use strict'; + +var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParsePromise = _dereq_('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var TaskQueue = function () { + function TaskQueue() { + (0, _classCallCheck3.default)(this, TaskQueue); + + this.queue = []; + } + + (0, _createClass3.default)(TaskQueue, [{ + key: 'enqueue', + value: function (task) { + var _this = this; + + var taskComplete = new _ParsePromise2.default(); + this.queue.push({ + task: task, + _completion: taskComplete + }); + if (this.queue.length === 1) { + task().then(function () { + _this._dequeue(); + taskComplete.resolve(); + }, function (error) { + _this._dequeue(); + taskComplete.reject(error); + }); + } + return taskComplete; + } + }, { + key: '_dequeue', + value: function () { + var _this2 = this; + + this.queue.shift(); + if (this.queue.length) { + var next = this.queue[0]; + next.task().then(function () { + _this2._dequeue(); + next._completion.resolve(); + }, function (error) { + _this2._dequeue(); + next._completion.reject(error); + }); + } + } + }]); + return TaskQueue; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = TaskQueue; +},{"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],32:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _weakMap = _dereq_('babel-runtime/core-js/weak-map'); + +var _weakMap2 = _interopRequireDefault(_weakMap); + +exports.getState = getState; +exports.initializeState = initializeState; +exports.removeState = removeState; +exports.getServerData = getServerData; +exports.setServerData = setServerData; +exports.getPendingOps = getPendingOps; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.getObjectCache = getObjectCache; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; +exports.enqueueTask = enqueueTask; +exports.duplicateState = duplicateState; +exports.clearAllState = clearAllState; + +var _ObjectStateMutations = _dereq_('./ObjectStateMutations'); + +var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); + +var _TaskQueue = _dereq_('./TaskQueue'); + +var _TaskQueue2 = _interopRequireDefault(_TaskQueue); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var objectState = new _weakMap2.default(); + +function getState(obj) { + var classData = objectState.get(obj); + return classData || null; +} + +function initializeState(obj, initial) { + var state = getState(obj); + if (state) { + return state; + } + if (!initial) { + initial = { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new _TaskQueue2.default(), + existed: false + }; + } + state = initial; + objectState.set(obj, state); + return state; +} + +function removeState(obj) { + var state = getState(obj); + if (state === null) { + return null; + } + objectState.delete(obj); + return state; +} + +function getServerData(obj) { + var state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +function setServerData(obj, attributes) { + var serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +function getPendingOps(obj) { + var state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +function setPendingOp(obj, attr, op) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +function pushPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +function popPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +function mergeFirstPendingState(obj) { + var pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +function getObjectCache(obj) { + var state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +function estimateAttribute(obj, attr) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +function estimateAttributes(obj) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +function commitServerChanges(obj, changes) { + var state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +function enqueueTask(obj, task) { + var state = initializeState(obj); + return state.tasks.enqueue(task); +} + +function duplicateState(source, dest) { + var oldState = initializeState(source); + var newState = initializeState(dest); + for (var key in oldState.serverData) { + newState.serverData[key] = oldState.serverData[key]; + } + for (var index = 0; index < oldState.pendingOps.length; index++) { + for (var _key in oldState.pendingOps[index]) { + newState.pendingOps[index][_key] = oldState.pendingOps[index][_key]; + } + } + for (var _key2 in oldState.objectCache) { + newState.objectCache[_key2] = oldState.objectCache[_key2]; + } + newState.existed = oldState.existed; +} + +function clearAllState() { + objectState = new _weakMap2.default(); +} +},{"./ObjectStateMutations":9,"./TaskQueue":31,"babel-runtime/core-js/weak-map":55}],33:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = arrayContainsObject; + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function arrayContainsObject(array, object) { + if (array.indexOf(object) > -1) { + return true; + } + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof _ParseObject2.default && array[i].className === object.className && array[i]._getId() === object._getId()) { + return true; + } + } + return false; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ +},{"./ParseObject":18}],34:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = canBeSerialized; + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function canBeSerialized(obj) { + if (!(obj instanceof _ParseObject2.default)) { + return true; + } + var attributes = obj.attributes; + for (var attr in attributes) { + var val = attributes[attr]; + if (!canBeSerializedHelper(val)) { + return false; + } + } + return true; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function canBeSerializedHelper(value) { + if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { + return true; + } + if (value instanceof _ParseRelation2.default) { + return true; + } + if (value instanceof _ParseObject2.default) { + return !!value.id; + } + if (value instanceof _ParseFile2.default) { + if (value.url()) { + return true; + } + return false; + } + if (Array.isArray(value)) { + for (var i = 0; i < value.length; i++) { + if (!canBeSerializedHelper(value[i])) { + return false; + } + } + return true; + } + for (var k in value) { + if (!canBeSerializedHelper(value[k])) { + return false; + } + } + return true; +} +},{"./ParseFile":14,"./ParseObject":18,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],35:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = decode; + +var _ParseACL = _dereq_('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseOp = _dereq_('./ParseOp'); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function decode(value) { + if (value === null || (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { + return value; + } + if (Array.isArray(value)) { + var dup = []; + value.forEach(function (v, i) { + dup[i] = decode(v); + }); + return dup; + } + if (typeof value.__op === 'string') { + return (0, _ParseOp.opFromJSON)(value); + } + if (value.__type === 'Pointer' && value.className) { + return _ParseObject2.default.fromJSON(value); + } + if (value.__type === 'Object' && value.className) { + return _ParseObject2.default.fromJSON(value); + } + if (value.__type === 'Relation') { + // The parent and key fields will be populated by the parent + var relation = new _ParseRelation2.default(null, null); + relation.targetClassName = value.className; + return relation; + } + if (value.__type === 'Date') { + return new Date(value.iso); + } + if (value.__type === 'File') { + return _ParseFile2.default.fromJSON(value); + } + if (value.__type === 'GeoPoint') { + return new _ParseGeoPoint2.default({ + latitude: value.latitude, + longitude: value.longitude + }); + } + var copy = {}; + for (var k in value) { + copy[k] = decode(value[k]); + } + return copy; +} +},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"./ParseOp":19,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],36:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _keys = _dereq_('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +exports.default = function (value, disallowObjects, forcePointers, seen) { + return encode(value, !!disallowObjects, !!forcePointers, seen || []); +}; + +var _ParseACL = _dereq_('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseOp = _dereq_('./ParseOp'); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var toString = Object.prototype.toString; + +function encode(value, disallowObjects, forcePointers, seen) { + if (value instanceof _ParseObject2.default) { + if (disallowObjects) { + throw new Error('Parse Objects not allowed here'); + } + var seenEntry = value.id ? value.className + ':' + value.id : value; + if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || (0, _keys2.default)(value._getServerData()).length < 1) { + return value.toPointer(); + } + seen = seen.concat(seenEntry); + return value._toFullJSON(seen); + } + if (value instanceof _ParseOp.Op || value instanceof _ParseACL2.default || value instanceof _ParseGeoPoint2.default || value instanceof _ParseRelation2.default) { + return value.toJSON(); + } + if (value instanceof _ParseFile2.default) { + if (!value.url()) { + throw new Error('Tried to encode an unsaved file.'); + } + return value.toJSON(); + } + if (toString.call(value) === '[object Date]') { + if (isNaN(value)) { + throw new Error('Tried to encode an invalid date.'); + } + return { __type: 'Date', iso: value.toJSON() }; + } + if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { + return value.source; + } + + if (Array.isArray(value)) { + return value.map(function (v) { + return encode(v, disallowObjects, forcePointers, seen); + }); + } + + if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { + var output = {}; + for (var k in value) { + output[k] = encode(value[k], disallowObjects, forcePointers, seen); + } + return output; + } + + return value; +} +},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"./ParseOp":19,"./ParseRelation":22,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],37:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _keys = _dereq_('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = equals; + +var _ParseACL = _dereq_('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +function equals(a, b) { + if ((typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== (typeof b === 'undefined' ? 'undefined' : (0, _typeof3.default)(b))) { + return false; + } + + if (!a || (typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== 'object') { + // a is a primitive + return a === b; + } + + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b)) { + return false; + } + if (a.length !== b.length) { + return false; + } + for (var i = a.length; i--;) { + if (!equals(a[i], b[i])) { + return false; + } + } + return true; + } + + if (a instanceof _ParseACL2.default || a instanceof _ParseFile2.default || a instanceof _ParseGeoPoint2.default || a instanceof _ParseObject2.default) { + return a.equals(b); + } + + if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) { + return false; + } + for (var k in a) { + if (!equals(a[k], b[k])) { + return false; + } + } + return true; +} +},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],38:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = escape; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var encoded = { + '&': '&', + '<': '<', + '>': '>', + '/': '/', + '\'': ''', + '"': '"' +}; + +function escape(str) { + return str.replace(/[&<>\/'"]/g, function (char) { + return encoded[char]; + }); +} +},{}],39:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = isRevocableSession; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function isRevocableSession(token) { + return token.indexOf('r:') > -1; +} +},{}],40:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = parseDate; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function parseDate(iso8601) { + var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); + var match = regexp.exec(iso8601); + if (!match) { + return null; + } + + var year = match[1] || 0; + var month = (match[2] || 1) - 1; + var day = match[3] || 0; + var hour = match[4] || 0; + var minute = match[5] || 0; + var second = match[6] || 0; + var milli = match[8] || 0; + + return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); +} +},{}],41:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = unique; + +var _arrayContainsObject = _dereq_('./arrayContainsObject'); + +var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function unique(arr) { + var uniques = []; + arr.forEach(function (value) { + if (value instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(uniques, value)) { + uniques.push(value); + } + } else { + if (uniques.indexOf(value) < 0) { + uniques.push(value); + } + } + }); + return uniques; +} +},{"./ParseObject":18,"./arrayContainsObject":33}],42:[function(_dereq_,module,exports){ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = unsavedChildren; + +var _ParseFile = _dereq_('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = _dereq_('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = _dereq_('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Return an array of unsaved children, which are either Parse Objects or Files. + * If it encounters any dirty Objects without Ids, it will throw an exception. + */ +function unsavedChildren(obj, allowDeepUnsaved) { + var encountered = { + objects: {}, + files: [] + }; + var identifier = obj.className + ':' + obj._getId(); + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if ((0, _typeof3.default)(attributes[attr]) === 'object') { + traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); + } + } + var unsaved = []; + for (var id in encountered.objects) { + if (id !== identifier && encountered.objects[id] !== true) { + unsaved.push(encountered.objects[id]); + } + } + return unsaved.concat(encountered.files); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { + if (obj instanceof _ParseObject2.default) { + if (!obj.id && shouldThrow) { + throw new Error('Cannot create a pointer to an unsaved Object.'); + } + var identifier = obj.className + ':' + obj._getId(); + if (!encountered.objects[identifier]) { + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if ((0, _typeof3.default)(attributes[attr]) === 'object') { + traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); + } + } + } + return; + } + if (obj instanceof _ParseFile2.default) { + if (!obj.url() && encountered.files.indexOf(obj) < 0) { + encountered.files.push(obj); + } + return; + } + if (obj instanceof _ParseRelation2.default) { + return; + } + if (Array.isArray(obj)) { + obj.forEach(function (el) { + if ((typeof el === 'undefined' ? 'undefined' : (0, _typeof3.default)(el)) === 'object') { + traverse(el, encountered, shouldThrow, allowDeepUnsaved); + } + }); + } + for (var k in obj) { + if ((0, _typeof3.default)(obj[k]) === 'object') { + traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); + } + } +} +},{"./ParseFile":14,"./ParseObject":18,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],43:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/get-iterator"), __esModule: true }; +},{"core-js/library/fn/get-iterator":62}],44:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/json/stringify"), __esModule: true }; +},{"core-js/library/fn/json/stringify":63}],45:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/map"), __esModule: true }; +},{"core-js/library/fn/map":64}],46:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/create"), __esModule: true }; +},{"core-js/library/fn/object/create":65}],47:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/define-property"), __esModule: true }; +},{"core-js/library/fn/object/define-property":66}],48:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/freeze"), __esModule: true }; +},{"core-js/library/fn/object/freeze":67}],49:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/get-own-property-descriptor"), __esModule: true }; +},{"core-js/library/fn/object/get-own-property-descriptor":68}],50:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/get-prototype-of"), __esModule: true }; +},{"core-js/library/fn/object/get-prototype-of":69}],51:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/keys"), __esModule: true }; +},{"core-js/library/fn/object/keys":70}],52:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/object/set-prototype-of"), __esModule: true }; +},{"core-js/library/fn/object/set-prototype-of":71}],53:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/symbol"), __esModule: true }; +},{"core-js/library/fn/symbol":72}],54:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/symbol/iterator"), __esModule: true }; +},{"core-js/library/fn/symbol/iterator":73}],55:[function(_dereq_,module,exports){ +module.exports = { "default": _dereq_("core-js/library/fn/weak-map"), __esModule: true }; +},{"core-js/library/fn/weak-map":74}],56:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +exports.default = function (instance, Constructor) { + if (!(instance instanceof Constructor)) { + throw new TypeError("Cannot call a class as a function"); + } +}; +},{}],57:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +var _defineProperty = _dereq_("../core-js/object/define-property"); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function () { + function defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + (0, _defineProperty2.default)(target, descriptor.key, descriptor); + } + } + + return function (Constructor, protoProps, staticProps) { + if (protoProps) defineProperties(Constructor.prototype, protoProps); + if (staticProps) defineProperties(Constructor, staticProps); + return Constructor; + }; +}(); +},{"../core-js/object/define-property":47}],58:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +var _getPrototypeOf = _dereq_("../core-js/object/get-prototype-of"); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _getOwnPropertyDescriptor = _dereq_("../core-js/object/get-own-property-descriptor"); + +var _getOwnPropertyDescriptor2 = _interopRequireDefault(_getOwnPropertyDescriptor); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function get(object, property, receiver) { + if (object === null) object = Function.prototype; + var desc = (0, _getOwnPropertyDescriptor2.default)(object, property); + + if (desc === undefined) { + var parent = (0, _getPrototypeOf2.default)(object); + + if (parent === null) { + return undefined; + } else { + return get(parent, property, receiver); + } + } else if ("value" in desc) { + return desc.value; + } else { + var getter = desc.get; + + if (getter === undefined) { + return undefined; + } + + return getter.call(receiver); + } +}; +},{"../core-js/object/get-own-property-descriptor":49,"../core-js/object/get-prototype-of":50}],59:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +var _setPrototypeOf = _dereq_("../core-js/object/set-prototype-of"); + +var _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf); + +var _create = _dereq_("../core-js/object/create"); + +var _create2 = _interopRequireDefault(_create); + +var _typeof2 = _dereq_("../helpers/typeof"); + +var _typeof3 = _interopRequireDefault(_typeof2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function (subClass, superClass) { + if (typeof superClass !== "function" && superClass !== null) { + throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : (0, _typeof3.default)(superClass))); + } + + subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, { + constructor: { + value: subClass, + enumerable: false, + writable: true, + configurable: true + } + }); + if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass; +}; +},{"../core-js/object/create":46,"../core-js/object/set-prototype-of":52,"../helpers/typeof":61}],60:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +var _typeof2 = _dereq_("../helpers/typeof"); + +var _typeof3 = _interopRequireDefault(_typeof2); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = function (self, call) { + if (!self) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self; +}; +},{"../helpers/typeof":61}],61:[function(_dereq_,module,exports){ +"use strict"; + +exports.__esModule = true; + +var _iterator = _dereq_("../core-js/symbol/iterator"); + +var _iterator2 = _interopRequireDefault(_iterator); + +var _symbol = _dereq_("../core-js/symbol"); + +var _symbol2 = _interopRequireDefault(_symbol); + +var _typeof = typeof _symbol2.default === "function" && typeof _iterator2.default === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; }; + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +exports.default = typeof _symbol2.default === "function" && _typeof(_iterator2.default) === "symbol" ? function (obj) { + return typeof obj === "undefined" ? "undefined" : _typeof(obj); +} : function (obj) { + return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof(obj); +}; +},{"../core-js/symbol":53,"../core-js/symbol/iterator":54}],62:[function(_dereq_,module,exports){ +_dereq_('../modules/web.dom.iterable'); +_dereq_('../modules/es6.string.iterator'); +module.exports = _dereq_('../modules/core.get-iterator'); +},{"../modules/core.get-iterator":150,"../modules/es6.string.iterator":161,"../modules/web.dom.iterable":167}],63:[function(_dereq_,module,exports){ +var core = _dereq_('../../modules/_core') + , $JSON = core.JSON || (core.JSON = {stringify: JSON.stringify}); +module.exports = function stringify(it){ // eslint-disable-line no-unused-vars + return $JSON.stringify.apply($JSON, arguments); +}; +},{"../../modules/_core":90}],64:[function(_dereq_,module,exports){ +_dereq_('../modules/es6.object.to-string'); +_dereq_('../modules/es6.string.iterator'); +_dereq_('../modules/web.dom.iterable'); +_dereq_('../modules/es6.map'); +_dereq_('../modules/es7.map.to-json'); +module.exports = _dereq_('../modules/_core').Map; +},{"../modules/_core":90,"../modules/es6.map":152,"../modules/es6.object.to-string":160,"../modules/es6.string.iterator":161,"../modules/es7.map.to-json":164,"../modules/web.dom.iterable":167}],65:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.create'); +var $Object = _dereq_('../../modules/_core').Object; +module.exports = function create(P, D){ + return $Object.create(P, D); +}; +},{"../../modules/_core":90,"../../modules/es6.object.create":153}],66:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.define-property'); +var $Object = _dereq_('../../modules/_core').Object; +module.exports = function defineProperty(it, key, desc){ + return $Object.defineProperty(it, key, desc); +}; +},{"../../modules/_core":90,"../../modules/es6.object.define-property":154}],67:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.freeze'); +module.exports = _dereq_('../../modules/_core').Object.freeze; +},{"../../modules/_core":90,"../../modules/es6.object.freeze":155}],68:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.get-own-property-descriptor'); +var $Object = _dereq_('../../modules/_core').Object; +module.exports = function getOwnPropertyDescriptor(it, key){ + return $Object.getOwnPropertyDescriptor(it, key); +}; +},{"../../modules/_core":90,"../../modules/es6.object.get-own-property-descriptor":156}],69:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.get-prototype-of'); +module.exports = _dereq_('../../modules/_core').Object.getPrototypeOf; +},{"../../modules/_core":90,"../../modules/es6.object.get-prototype-of":157}],70:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.keys'); +module.exports = _dereq_('../../modules/_core').Object.keys; +},{"../../modules/_core":90,"../../modules/es6.object.keys":158}],71:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.object.set-prototype-of'); +module.exports = _dereq_('../../modules/_core').Object.setPrototypeOf; +},{"../../modules/_core":90,"../../modules/es6.object.set-prototype-of":159}],72:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.symbol'); +_dereq_('../../modules/es6.object.to-string'); +_dereq_('../../modules/es7.symbol.async-iterator'); +_dereq_('../../modules/es7.symbol.observable'); +module.exports = _dereq_('../../modules/_core').Symbol; +},{"../../modules/_core":90,"../../modules/es6.object.to-string":160,"../../modules/es6.symbol":162,"../../modules/es7.symbol.async-iterator":165,"../../modules/es7.symbol.observable":166}],73:[function(_dereq_,module,exports){ +_dereq_('../../modules/es6.string.iterator'); +_dereq_('../../modules/web.dom.iterable'); +module.exports = _dereq_('../../modules/_wks-ext').f('iterator'); +},{"../../modules/_wks-ext":147,"../../modules/es6.string.iterator":161,"../../modules/web.dom.iterable":167}],74:[function(_dereq_,module,exports){ +_dereq_('../modules/es6.object.to-string'); +_dereq_('../modules/web.dom.iterable'); +_dereq_('../modules/es6.weak-map'); +module.exports = _dereq_('../modules/_core').WeakMap; +},{"../modules/_core":90,"../modules/es6.object.to-string":160,"../modules/es6.weak-map":163,"../modules/web.dom.iterable":167}],75:[function(_dereq_,module,exports){ +module.exports = function(it){ + if(typeof it != 'function')throw TypeError(it + ' is not a function!'); + return it; +}; +},{}],76:[function(_dereq_,module,exports){ +module.exports = function(){ /* empty */ }; +},{}],77:[function(_dereq_,module,exports){ +module.exports = function(it, Constructor, name, forbiddenField){ + if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){ + throw TypeError(name + ': incorrect invocation!'); + } return it; +}; +},{}],78:[function(_dereq_,module,exports){ +var isObject = _dereq_('./_is-object'); +module.exports = function(it){ + if(!isObject(it))throw TypeError(it + ' is not an object!'); + return it; +}; +},{"./_is-object":108}],79:[function(_dereq_,module,exports){ +var forOf = _dereq_('./_for-of'); + +module.exports = function(iter, ITERATOR){ + var result = []; + forOf(iter, false, result.push, result, ITERATOR); + return result; +}; + +},{"./_for-of":99}],80:[function(_dereq_,module,exports){ +// false -> Array#indexOf +// true -> Array#includes +var toIObject = _dereq_('./_to-iobject') + , toLength = _dereq_('./_to-length') + , toIndex = _dereq_('./_to-index'); +module.exports = function(IS_INCLUDES){ + return function($this, el, fromIndex){ + var O = toIObject($this) + , length = toLength(O.length) + , index = toIndex(fromIndex, length) + , value; + // Array#includes uses SameValueZero equality algorithm + if(IS_INCLUDES && el != el)while(length > index){ + value = O[index++]; + if(value != value)return true; + // Array#toIndex ignores holes, Array#includes - not + } else for(;length > index; index++)if(IS_INCLUDES || index in O){ + if(O[index] === el)return IS_INCLUDES || index || 0; + } return !IS_INCLUDES && -1; + }; +}; +},{"./_to-index":139,"./_to-iobject":141,"./_to-length":142}],81:[function(_dereq_,module,exports){ +// 0 -> Array#forEach +// 1 -> Array#map +// 2 -> Array#filter +// 3 -> Array#some +// 4 -> Array#every +// 5 -> Array#find +// 6 -> Array#findIndex +var ctx = _dereq_('./_ctx') + , IObject = _dereq_('./_iobject') + , toObject = _dereq_('./_to-object') + , toLength = _dereq_('./_to-length') + , asc = _dereq_('./_array-species-create'); +module.exports = function(TYPE, $create){ + var IS_MAP = TYPE == 1 + , IS_FILTER = TYPE == 2 + , IS_SOME = TYPE == 3 + , IS_EVERY = TYPE == 4 + , IS_FIND_INDEX = TYPE == 6 + , NO_HOLES = TYPE == 5 || IS_FIND_INDEX + , create = $create || asc; + return function($this, callbackfn, that){ + var O = toObject($this) + , self = IObject(O) + , f = ctx(callbackfn, that, 3) + , length = toLength(self.length) + , index = 0 + , result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined + , val, res; + for(;length > index; index++)if(NO_HOLES || index in self){ + val = self[index]; + res = f(val, index, O); + if(TYPE){ + if(IS_MAP)result[index] = res; // map + else if(res)switch(TYPE){ + case 3: return true; // some + case 5: return val; // find + case 6: return index; // findIndex + case 2: result.push(val); // filter + } else if(IS_EVERY)return false; // every + } + } + return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result; + }; +}; +},{"./_array-species-create":83,"./_ctx":91,"./_iobject":105,"./_to-length":142,"./_to-object":143}],82:[function(_dereq_,module,exports){ +var isObject = _dereq_('./_is-object') + , isArray = _dereq_('./_is-array') + , SPECIES = _dereq_('./_wks')('species'); + +module.exports = function(original){ + var C; + if(isArray(original)){ + C = original.constructor; + // cross-realm fallback + if(typeof C == 'function' && (C === Array || isArray(C.prototype)))C = undefined; + if(isObject(C)){ + C = C[SPECIES]; + if(C === null)C = undefined; + } + } return C === undefined ? Array : C; +}; +},{"./_is-array":107,"./_is-object":108,"./_wks":148}],83:[function(_dereq_,module,exports){ +// 9.4.2.3 ArraySpeciesCreate(originalArray, length) +var speciesConstructor = _dereq_('./_array-species-constructor'); + +module.exports = function(original, length){ + return new (speciesConstructor(original))(length); +}; +},{"./_array-species-constructor":82}],84:[function(_dereq_,module,exports){ +// getting tag from 19.1.3.6 Object.prototype.toString() +var cof = _dereq_('./_cof') + , TAG = _dereq_('./_wks')('toStringTag') + // ES3 wrong here + , ARG = cof(function(){ return arguments; }()) == 'Arguments'; + +// fallback for IE11 Script Access Denied error +var tryGet = function(it, key){ + try { + return it[key]; + } catch(e){ /* empty */ } +}; + +module.exports = function(it){ + var O, T, B; + return it === undefined ? 'Undefined' : it === null ? 'Null' + // @@toStringTag case + : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T + // builtinTag case + : ARG ? cof(O) + // ES3 arguments fallback + : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; +}; +},{"./_cof":85,"./_wks":148}],85:[function(_dereq_,module,exports){ +var toString = {}.toString; + +module.exports = function(it){ + return toString.call(it).slice(8, -1); +}; +},{}],86:[function(_dereq_,module,exports){ +'use strict'; +var dP = _dereq_('./_object-dp').f + , create = _dereq_('./_object-create') + , redefineAll = _dereq_('./_redefine-all') + , ctx = _dereq_('./_ctx') + , anInstance = _dereq_('./_an-instance') + , defined = _dereq_('./_defined') + , forOf = _dereq_('./_for-of') + , $iterDefine = _dereq_('./_iter-define') + , step = _dereq_('./_iter-step') + , setSpecies = _dereq_('./_set-species') + , DESCRIPTORS = _dereq_('./_descriptors') + , fastKey = _dereq_('./_meta').fastKey + , SIZE = DESCRIPTORS ? '_s' : 'size'; + +var getEntry = function(that, key){ + // fast case + var index = fastKey(key), entry; + if(index !== 'F')return that._i[index]; + // frozen object case + for(entry = that._f; entry; entry = entry.n){ + if(entry.k == key)return entry; + } +}; + +module.exports = { + getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ + var C = wrapper(function(that, iterable){ + anInstance(that, C, NAME, '_i'); + that._i = create(null); // index + that._f = undefined; // first entry + that._l = undefined; // last entry + that[SIZE] = 0; // size + if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); + }); + redefineAll(C.prototype, { + // 23.1.3.1 Map.prototype.clear() + // 23.2.3.2 Set.prototype.clear() + clear: function clear(){ + for(var that = this, data = that._i, entry = that._f; entry; entry = entry.n){ + entry.r = true; + if(entry.p)entry.p = entry.p.n = undefined; + delete data[entry.i]; + } + that._f = that._l = undefined; + that[SIZE] = 0; + }, + // 23.1.3.3 Map.prototype.delete(key) + // 23.2.3.4 Set.prototype.delete(value) + 'delete': function(key){ + var that = this + , entry = getEntry(that, key); + if(entry){ + var next = entry.n + , prev = entry.p; + delete that._i[entry.i]; + entry.r = true; + if(prev)prev.n = next; + if(next)next.p = prev; + if(that._f == entry)that._f = next; + if(that._l == entry)that._l = prev; + that[SIZE]--; + } return !!entry; + }, + // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) + // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) + forEach: function forEach(callbackfn /*, that = undefined */){ + anInstance(this, C, 'forEach'); + var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3) + , entry; + while(entry = entry ? entry.n : this._f){ + f(entry.v, entry.k, this); + // revert to the last existing entry + while(entry && entry.r)entry = entry.p; + } + }, + // 23.1.3.7 Map.prototype.has(key) + // 23.2.3.7 Set.prototype.has(value) + has: function has(key){ + return !!getEntry(this, key); + } + }); + if(DESCRIPTORS)dP(C.prototype, 'size', { + get: function(){ + return defined(this[SIZE]); + } + }); + return C; + }, + def: function(that, key, value){ + var entry = getEntry(that, key) + , prev, index; + // change existing entry + if(entry){ + entry.v = value; + // create new entry + } else { + that._l = entry = { + i: index = fastKey(key, true), // <- index + k: key, // <- key + v: value, // <- value + p: prev = that._l, // <- previous entry + n: undefined, // <- next entry + r: false // <- removed + }; + if(!that._f)that._f = entry; + if(prev)prev.n = entry; + that[SIZE]++; + // add to index + if(index !== 'F')that._i[index] = entry; + } return that; + }, + getEntry: getEntry, + setStrong: function(C, NAME, IS_MAP){ + // add .keys, .values, .entries, [@@iterator] + // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11 + $iterDefine(C, NAME, function(iterated, kind){ + this._t = iterated; // target + this._k = kind; // kind + this._l = undefined; // previous + }, function(){ + var that = this + , kind = that._k + , entry = that._l; + // revert to the last existing entry + while(entry && entry.r)entry = entry.p; + // get next entry + if(!that._t || !(that._l = entry = entry ? entry.n : that._t._f)){ + // or finish the iteration + that._t = undefined; + return step(1); + } + // return step by kind + if(kind == 'keys' )return step(0, entry.k); + if(kind == 'values')return step(0, entry.v); + return step(0, [entry.k, entry.v]); + }, IS_MAP ? 'entries' : 'values' , !IS_MAP, true); + + // add [@@species], 23.1.2.2, 23.2.2.2 + setSpecies(NAME); + } +}; +},{"./_an-instance":77,"./_ctx":91,"./_defined":92,"./_descriptors":93,"./_for-of":99,"./_iter-define":111,"./_iter-step":112,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_redefine-all":131,"./_set-species":134}],87:[function(_dereq_,module,exports){ +// https://github.com/DavidBruant/Map-Set.prototype.toJSON +var classof = _dereq_('./_classof') + , from = _dereq_('./_array-from-iterable'); +module.exports = function(NAME){ + return function toJSON(){ + if(classof(this) != NAME)throw TypeError(NAME + "#toJSON isn't generic"); + return from(this); + }; +}; +},{"./_array-from-iterable":79,"./_classof":84}],88:[function(_dereq_,module,exports){ +'use strict'; +var redefineAll = _dereq_('./_redefine-all') + , getWeak = _dereq_('./_meta').getWeak + , anObject = _dereq_('./_an-object') + , isObject = _dereq_('./_is-object') + , anInstance = _dereq_('./_an-instance') + , forOf = _dereq_('./_for-of') + , createArrayMethod = _dereq_('./_array-methods') + , $has = _dereq_('./_has') + , arrayFind = createArrayMethod(5) + , arrayFindIndex = createArrayMethod(6) + , id = 0; + +// fallback for uncaught frozen keys +var uncaughtFrozenStore = function(that){ + return that._l || (that._l = new UncaughtFrozenStore); +}; +var UncaughtFrozenStore = function(){ + this.a = []; +}; +var findUncaughtFrozen = function(store, key){ + return arrayFind(store.a, function(it){ + return it[0] === key; + }); +}; +UncaughtFrozenStore.prototype = { + get: function(key){ + var entry = findUncaughtFrozen(this, key); + if(entry)return entry[1]; + }, + has: function(key){ + return !!findUncaughtFrozen(this, key); + }, + set: function(key, value){ + var entry = findUncaughtFrozen(this, key); + if(entry)entry[1] = value; + else this.a.push([key, value]); + }, + 'delete': function(key){ + var index = arrayFindIndex(this.a, function(it){ + return it[0] === key; + }); + if(~index)this.a.splice(index, 1); + return !!~index; + } +}; + +module.exports = { + getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ + var C = wrapper(function(that, iterable){ + anInstance(that, C, NAME, '_i'); + that._i = id++; // collection id + that._l = undefined; // leak store for uncaught frozen objects + if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); + }); + redefineAll(C.prototype, { + // 23.3.3.2 WeakMap.prototype.delete(key) + // 23.4.3.3 WeakSet.prototype.delete(value) + 'delete': function(key){ + if(!isObject(key))return false; + var data = getWeak(key); + if(data === true)return uncaughtFrozenStore(this)['delete'](key); + return data && $has(data, this._i) && delete data[this._i]; + }, + // 23.3.3.4 WeakMap.prototype.has(key) + // 23.4.3.4 WeakSet.prototype.has(value) + has: function has(key){ + if(!isObject(key))return false; + var data = getWeak(key); + if(data === true)return uncaughtFrozenStore(this).has(key); + return data && $has(data, this._i); + } + }); + return C; + }, + def: function(that, key, value){ + var data = getWeak(anObject(key), true); + if(data === true)uncaughtFrozenStore(that).set(key, value); + else data[that._i] = value; + return that; + }, + ufstore: uncaughtFrozenStore +}; +},{"./_an-instance":77,"./_an-object":78,"./_array-methods":81,"./_for-of":99,"./_has":101,"./_is-object":108,"./_meta":116,"./_redefine-all":131}],89:[function(_dereq_,module,exports){ +'use strict'; +var global = _dereq_('./_global') + , $export = _dereq_('./_export') + , meta = _dereq_('./_meta') + , fails = _dereq_('./_fails') + , hide = _dereq_('./_hide') + , redefineAll = _dereq_('./_redefine-all') + , forOf = _dereq_('./_for-of') + , anInstance = _dereq_('./_an-instance') + , isObject = _dereq_('./_is-object') + , setToStringTag = _dereq_('./_set-to-string-tag') + , dP = _dereq_('./_object-dp').f + , each = _dereq_('./_array-methods')(0) + , DESCRIPTORS = _dereq_('./_descriptors'); + +module.exports = function(NAME, wrapper, methods, common, IS_MAP, IS_WEAK){ + var Base = global[NAME] + , C = Base + , ADDER = IS_MAP ? 'set' : 'add' + , proto = C && C.prototype + , O = {}; + if(!DESCRIPTORS || typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function(){ + new C().entries().next(); + }))){ + // create collection constructor + C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER); + redefineAll(C.prototype, methods); + meta.NEED = true; + } else { + C = wrapper(function(target, iterable){ + anInstance(target, C, NAME, '_c'); + target._c = new Base; + if(iterable != undefined)forOf(iterable, IS_MAP, target[ADDER], target); + }); + each('add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON'.split(','),function(KEY){ + var IS_ADDER = KEY == 'add' || KEY == 'set'; + if(KEY in proto && !(IS_WEAK && KEY == 'clear'))hide(C.prototype, KEY, function(a, b){ + anInstance(this, C, KEY); + if(!IS_ADDER && IS_WEAK && !isObject(a))return KEY == 'get' ? undefined : false; + var result = this._c[KEY](a === 0 ? 0 : a, b); + return IS_ADDER ? this : result; + }); + }); + if('size' in proto)dP(C.prototype, 'size', { + get: function(){ + return this._c.size; + } + }); + } + + setToStringTag(C, NAME); + + O[NAME] = C; + $export($export.G + $export.W + $export.F, O); + + if(!IS_WEAK)common.setStrong(C, NAME, IS_MAP); + + return C; +}; +},{"./_an-instance":77,"./_array-methods":81,"./_descriptors":93,"./_export":97,"./_fails":98,"./_for-of":99,"./_global":100,"./_hide":102,"./_is-object":108,"./_meta":116,"./_object-dp":119,"./_redefine-all":131,"./_set-to-string-tag":135}],90:[function(_dereq_,module,exports){ +var core = module.exports = {version: '2.4.0'}; +if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef +},{}],91:[function(_dereq_,module,exports){ +// optional / simple context binding +var aFunction = _dereq_('./_a-function'); +module.exports = function(fn, that, length){ + aFunction(fn); + if(that === undefined)return fn; + switch(length){ + case 1: return function(a){ + return fn.call(that, a); + }; + case 2: return function(a, b){ + return fn.call(that, a, b); + }; + case 3: return function(a, b, c){ + return fn.call(that, a, b, c); + }; + } + return function(/* ...args */){ + return fn.apply(that, arguments); + }; +}; +},{"./_a-function":75}],92:[function(_dereq_,module,exports){ +// 7.2.1 RequireObjectCoercible(argument) +module.exports = function(it){ + if(it == undefined)throw TypeError("Can't call method on " + it); + return it; +}; +},{}],93:[function(_dereq_,module,exports){ +// Thank's IE8 for his funny defineProperty +module.exports = !_dereq_('./_fails')(function(){ + return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7; +}); +},{"./_fails":98}],94:[function(_dereq_,module,exports){ +var isObject = _dereq_('./_is-object') + , document = _dereq_('./_global').document + // in old IE typeof document.createElement is 'object' + , is = isObject(document) && isObject(document.createElement); +module.exports = function(it){ + return is ? document.createElement(it) : {}; +}; +},{"./_global":100,"./_is-object":108}],95:[function(_dereq_,module,exports){ +// IE 8- don't enum bug keys +module.exports = ( + 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' +).split(','); +},{}],96:[function(_dereq_,module,exports){ +// all enumerable object keys, includes symbols +var getKeys = _dereq_('./_object-keys') + , gOPS = _dereq_('./_object-gops') + , pIE = _dereq_('./_object-pie'); +module.exports = function(it){ + var result = getKeys(it) + , getSymbols = gOPS.f; + if(getSymbols){ + var symbols = getSymbols(it) + , isEnum = pIE.f + , i = 0 + , key; + while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))result.push(key); + } return result; +}; +},{"./_object-gops":124,"./_object-keys":127,"./_object-pie":128}],97:[function(_dereq_,module,exports){ +var global = _dereq_('./_global') + , core = _dereq_('./_core') + , ctx = _dereq_('./_ctx') + , hide = _dereq_('./_hide') + , PROTOTYPE = 'prototype'; + +var $export = function(type, name, source){ + var IS_FORCED = type & $export.F + , IS_GLOBAL = type & $export.G + , IS_STATIC = type & $export.S + , IS_PROTO = type & $export.P + , IS_BIND = type & $export.B + , IS_WRAP = type & $export.W + , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) + , expProto = exports[PROTOTYPE] + , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] + , key, own, out; + if(IS_GLOBAL)source = name; + for(key in source){ + // contains in native + own = !IS_FORCED && target && target[key] !== undefined; + if(own && key in exports)continue; + // export native or passed + out = own ? target[key] : source[key]; + // prevent global pollution for namespaces + exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] + // bind timers to global for call from export context + : IS_BIND && own ? ctx(out, global) + // wrap global constructors for prevent change them in library + : IS_WRAP && target[key] == out ? (function(C){ + var F = function(a, b, c){ + if(this instanceof C){ + switch(arguments.length){ + case 0: return new C; + case 1: return new C(a); + case 2: return new C(a, b); + } return new C(a, b, c); + } return C.apply(this, arguments); + }; + F[PROTOTYPE] = C[PROTOTYPE]; + return F; + // make static versions for prototype methods + })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; + // export proto methods to core.%CONSTRUCTOR%.methods.%NAME% + if(IS_PROTO){ + (exports.virtual || (exports.virtual = {}))[key] = out; + // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME% + if(type & $export.R && expProto && !expProto[key])hide(expProto, key, out); + } + } +}; +// type bitmap +$export.F = 1; // forced +$export.G = 2; // global +$export.S = 4; // static +$export.P = 8; // proto +$export.B = 16; // bind +$export.W = 32; // wrap +$export.U = 64; // safe +$export.R = 128; // real proto method for `library` +module.exports = $export; +},{"./_core":90,"./_ctx":91,"./_global":100,"./_hide":102}],98:[function(_dereq_,module,exports){ +module.exports = function(exec){ + try { + return !!exec(); + } catch(e){ + return true; + } +}; +},{}],99:[function(_dereq_,module,exports){ +var ctx = _dereq_('./_ctx') + , call = _dereq_('./_iter-call') + , isArrayIter = _dereq_('./_is-array-iter') + , anObject = _dereq_('./_an-object') + , toLength = _dereq_('./_to-length') + , getIterFn = _dereq_('./core.get-iterator-method') + , BREAK = {} + , RETURN = {}; +var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){ + var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable) + , f = ctx(fn, that, entries ? 2 : 1) + , index = 0 + , length, step, iterator, result; + if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!'); + // fast case for arrays with default iterator + if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){ + result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]); + if(result === BREAK || result === RETURN)return result; + } else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){ + result = call(iterator, f, step.value, entries); + if(result === BREAK || result === RETURN)return result; + } +}; +exports.BREAK = BREAK; +exports.RETURN = RETURN; +},{"./_an-object":78,"./_ctx":91,"./_is-array-iter":106,"./_iter-call":109,"./_to-length":142,"./core.get-iterator-method":149}],100:[function(_dereq_,module,exports){ +// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 +var global = module.exports = typeof window != 'undefined' && window.Math == Math + ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); +if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef +},{}],101:[function(_dereq_,module,exports){ +var hasOwnProperty = {}.hasOwnProperty; +module.exports = function(it, key){ + return hasOwnProperty.call(it, key); +}; +},{}],102:[function(_dereq_,module,exports){ +var dP = _dereq_('./_object-dp') + , createDesc = _dereq_('./_property-desc'); +module.exports = _dereq_('./_descriptors') ? function(object, key, value){ + return dP.f(object, key, createDesc(1, value)); +} : function(object, key, value){ + object[key] = value; + return object; +}; +},{"./_descriptors":93,"./_object-dp":119,"./_property-desc":130}],103:[function(_dereq_,module,exports){ +module.exports = _dereq_('./_global').document && document.documentElement; +},{"./_global":100}],104:[function(_dereq_,module,exports){ +module.exports = !_dereq_('./_descriptors') && !_dereq_('./_fails')(function(){ + return Object.defineProperty(_dereq_('./_dom-create')('div'), 'a', {get: function(){ return 7; }}).a != 7; +}); +},{"./_descriptors":93,"./_dom-create":94,"./_fails":98}],105:[function(_dereq_,module,exports){ +// fallback for non-array-like ES3 and non-enumerable old V8 strings +var cof = _dereq_('./_cof'); +module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){ + return cof(it) == 'String' ? it.split('') : Object(it); +}; +},{"./_cof":85}],106:[function(_dereq_,module,exports){ +// check on default Array iterator +var Iterators = _dereq_('./_iterators') + , ITERATOR = _dereq_('./_wks')('iterator') + , ArrayProto = Array.prototype; + +module.exports = function(it){ + return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it); +}; +},{"./_iterators":113,"./_wks":148}],107:[function(_dereq_,module,exports){ +// 7.2.2 IsArray(argument) +var cof = _dereq_('./_cof'); +module.exports = Array.isArray || function isArray(arg){ + return cof(arg) == 'Array'; +}; +},{"./_cof":85}],108:[function(_dereq_,module,exports){ +module.exports = function(it){ + return typeof it === 'object' ? it !== null : typeof it === 'function'; +}; +},{}],109:[function(_dereq_,module,exports){ +// call something on iterator step with safe closing on error +var anObject = _dereq_('./_an-object'); +module.exports = function(iterator, fn, value, entries){ + try { + return entries ? fn(anObject(value)[0], value[1]) : fn(value); + // 7.4.6 IteratorClose(iterator, completion) + } catch(e){ + var ret = iterator['return']; + if(ret !== undefined)anObject(ret.call(iterator)); + throw e; + } +}; +},{"./_an-object":78}],110:[function(_dereq_,module,exports){ +'use strict'; +var create = _dereq_('./_object-create') + , descriptor = _dereq_('./_property-desc') + , setToStringTag = _dereq_('./_set-to-string-tag') + , IteratorPrototype = {}; + +// 25.1.2.1.1 %IteratorPrototype%[@@iterator]() +_dereq_('./_hide')(IteratorPrototype, _dereq_('./_wks')('iterator'), function(){ return this; }); + +module.exports = function(Constructor, NAME, next){ + Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)}); + setToStringTag(Constructor, NAME + ' Iterator'); +}; +},{"./_hide":102,"./_object-create":118,"./_property-desc":130,"./_set-to-string-tag":135,"./_wks":148}],111:[function(_dereq_,module,exports){ +'use strict'; +var LIBRARY = _dereq_('./_library') + , $export = _dereq_('./_export') + , redefine = _dereq_('./_redefine') + , hide = _dereq_('./_hide') + , has = _dereq_('./_has') + , Iterators = _dereq_('./_iterators') + , $iterCreate = _dereq_('./_iter-create') + , setToStringTag = _dereq_('./_set-to-string-tag') + , getPrototypeOf = _dereq_('./_object-gpo') + , ITERATOR = _dereq_('./_wks')('iterator') + , BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next` + , FF_ITERATOR = '@@iterator' + , KEYS = 'keys' + , VALUES = 'values'; + +var returnThis = function(){ return this; }; + +module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){ + $iterCreate(Constructor, NAME, next); + var getMethod = function(kind){ + if(!BUGGY && kind in proto)return proto[kind]; + switch(kind){ + case KEYS: return function keys(){ return new Constructor(this, kind); }; + case VALUES: return function values(){ return new Constructor(this, kind); }; + } return function entries(){ return new Constructor(this, kind); }; + }; + var TAG = NAME + ' Iterator' + , DEF_VALUES = DEFAULT == VALUES + , VALUES_BUG = false + , proto = Base.prototype + , $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT] + , $default = $native || getMethod(DEFAULT) + , $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined + , $anyNative = NAME == 'Array' ? proto.entries || $native : $native + , methods, key, IteratorPrototype; + // Fix native + if($anyNative){ + IteratorPrototype = getPrototypeOf($anyNative.call(new Base)); + if(IteratorPrototype !== Object.prototype){ + // Set @@toStringTag to native iterators + setToStringTag(IteratorPrototype, TAG, true); + // fix for some old engines + if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis); + } + } + // fix Array#{values, @@iterator}.name in V8 / FF + if(DEF_VALUES && $native && $native.name !== VALUES){ + VALUES_BUG = true; + $default = function values(){ return $native.call(this); }; + } + // Define iterator + if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){ + hide(proto, ITERATOR, $default); + } + // Plug for library + Iterators[NAME] = $default; + Iterators[TAG] = returnThis; + if(DEFAULT){ + methods = { + values: DEF_VALUES ? $default : getMethod(VALUES), + keys: IS_SET ? $default : getMethod(KEYS), + entries: $entries + }; + if(FORCED)for(key in methods){ + if(!(key in proto))redefine(proto, key, methods[key]); + } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); + } + return methods; +}; +},{"./_export":97,"./_has":101,"./_hide":102,"./_iter-create":110,"./_iterators":113,"./_library":115,"./_object-gpo":125,"./_redefine":132,"./_set-to-string-tag":135,"./_wks":148}],112:[function(_dereq_,module,exports){ +module.exports = function(done, value){ + return {value: value, done: !!done}; +}; +},{}],113:[function(_dereq_,module,exports){ +module.exports = {}; +},{}],114:[function(_dereq_,module,exports){ +var getKeys = _dereq_('./_object-keys') + , toIObject = _dereq_('./_to-iobject'); +module.exports = function(object, el){ + var O = toIObject(object) + , keys = getKeys(O) + , length = keys.length + , index = 0 + , key; + while(length > index)if(O[key = keys[index++]] === el)return key; +}; +},{"./_object-keys":127,"./_to-iobject":141}],115:[function(_dereq_,module,exports){ +module.exports = true; +},{}],116:[function(_dereq_,module,exports){ +var META = _dereq_('./_uid')('meta') + , isObject = _dereq_('./_is-object') + , has = _dereq_('./_has') + , setDesc = _dereq_('./_object-dp').f + , id = 0; +var isExtensible = Object.isExtensible || function(){ + return true; +}; +var FREEZE = !_dereq_('./_fails')(function(){ + return isExtensible(Object.preventExtensions({})); +}); +var setMeta = function(it){ + setDesc(it, META, {value: { + i: 'O' + ++id, // object ID + w: {} // weak collections IDs + }}); +}; +var fastKey = function(it, create){ + // return primitive with prefix + if(!isObject(it))return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it; + if(!has(it, META)){ + // can't set metadata to uncaught frozen object + if(!isExtensible(it))return 'F'; + // not necessary to add metadata + if(!create)return 'E'; + // add missing metadata + setMeta(it); + // return object ID + } return it[META].i; +}; +var getWeak = function(it, create){ + if(!has(it, META)){ + // can't set metadata to uncaught frozen object + if(!isExtensible(it))return true; + // not necessary to add metadata + if(!create)return false; + // add missing metadata + setMeta(it); + // return hash weak collections IDs + } return it[META].w; +}; +// add metadata on freeze-family methods calling +var onFreeze = function(it){ + if(FREEZE && meta.NEED && isExtensible(it) && !has(it, META))setMeta(it); + return it; +}; +var meta = module.exports = { + KEY: META, + NEED: false, + fastKey: fastKey, + getWeak: getWeak, + onFreeze: onFreeze +}; +},{"./_fails":98,"./_has":101,"./_is-object":108,"./_object-dp":119,"./_uid":145}],117:[function(_dereq_,module,exports){ +'use strict'; +// 19.1.2.1 Object.assign(target, source, ...) +var getKeys = _dereq_('./_object-keys') + , gOPS = _dereq_('./_object-gops') + , pIE = _dereq_('./_object-pie') + , toObject = _dereq_('./_to-object') + , IObject = _dereq_('./_iobject') + , $assign = Object.assign; + +// should work with symbols and should have deterministic property order (V8 bug) +module.exports = !$assign || _dereq_('./_fails')(function(){ + var A = {} + , B = {} + , S = Symbol() + , K = 'abcdefghijklmnopqrst'; + A[S] = 7; + K.split('').forEach(function(k){ B[k] = k; }); + return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K; +}) ? function assign(target, source){ // eslint-disable-line no-unused-vars + var T = toObject(target) + , aLen = arguments.length + , index = 1 + , getSymbols = gOPS.f + , isEnum = pIE.f; + while(aLen > index){ + var S = IObject(arguments[index++]) + , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S) + , length = keys.length + , j = 0 + , key; + while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key]; + } return T; +} : $assign; +},{"./_fails":98,"./_iobject":105,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_to-object":143}],118:[function(_dereq_,module,exports){ +// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) +var anObject = _dereq_('./_an-object') + , dPs = _dereq_('./_object-dps') + , enumBugKeys = _dereq_('./_enum-bug-keys') + , IE_PROTO = _dereq_('./_shared-key')('IE_PROTO') + , Empty = function(){ /* empty */ } + , PROTOTYPE = 'prototype'; + +// Create object with fake `null` prototype: use iframe Object with cleared prototype +var createDict = function(){ + // Thrash, waste and sodomy: IE GC bug + var iframe = _dereq_('./_dom-create')('iframe') + , i = enumBugKeys.length + , lt = '<' + , gt = '>' + , iframeDocument; + iframe.style.display = 'none'; + _dereq_('./_html').appendChild(iframe); + iframe.src = 'javascript:'; // eslint-disable-line no-script-url + // createDict = iframe.contentWindow.Object; + // html.removeChild(iframe); + iframeDocument = iframe.contentWindow.document; + iframeDocument.open(); + iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt); + iframeDocument.close(); + createDict = iframeDocument.F; + while(i--)delete createDict[PROTOTYPE][enumBugKeys[i]]; + return createDict(); +}; + +module.exports = Object.create || function create(O, Properties){ + var result; + if(O !== null){ + Empty[PROTOTYPE] = anObject(O); + result = new Empty; + Empty[PROTOTYPE] = null; + // add "__proto__" for Object.getPrototypeOf polyfill + result[IE_PROTO] = O; + } else result = createDict(); + return Properties === undefined ? result : dPs(result, Properties); +}; + +},{"./_an-object":78,"./_dom-create":94,"./_enum-bug-keys":95,"./_html":103,"./_object-dps":120,"./_shared-key":136}],119:[function(_dereq_,module,exports){ +var anObject = _dereq_('./_an-object') + , IE8_DOM_DEFINE = _dereq_('./_ie8-dom-define') + , toPrimitive = _dereq_('./_to-primitive') + , dP = Object.defineProperty; + +exports.f = _dereq_('./_descriptors') ? Object.defineProperty : function defineProperty(O, P, Attributes){ + anObject(O); + P = toPrimitive(P, true); + anObject(Attributes); + if(IE8_DOM_DEFINE)try { + return dP(O, P, Attributes); + } catch(e){ /* empty */ } + if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!'); + if('value' in Attributes)O[P] = Attributes.value; + return O; +}; +},{"./_an-object":78,"./_descriptors":93,"./_ie8-dom-define":104,"./_to-primitive":144}],120:[function(_dereq_,module,exports){ +var dP = _dereq_('./_object-dp') + , anObject = _dereq_('./_an-object') + , getKeys = _dereq_('./_object-keys'); + +module.exports = _dereq_('./_descriptors') ? Object.defineProperties : function defineProperties(O, Properties){ + anObject(O); + var keys = getKeys(Properties) + , length = keys.length + , i = 0 + , P; + while(length > i)dP.f(O, P = keys[i++], Properties[P]); + return O; +}; +},{"./_an-object":78,"./_descriptors":93,"./_object-dp":119,"./_object-keys":127}],121:[function(_dereq_,module,exports){ +var pIE = _dereq_('./_object-pie') + , createDesc = _dereq_('./_property-desc') + , toIObject = _dereq_('./_to-iobject') + , toPrimitive = _dereq_('./_to-primitive') + , has = _dereq_('./_has') + , IE8_DOM_DEFINE = _dereq_('./_ie8-dom-define') + , gOPD = Object.getOwnPropertyDescriptor; + +exports.f = _dereq_('./_descriptors') ? gOPD : function getOwnPropertyDescriptor(O, P){ + O = toIObject(O); + P = toPrimitive(P, true); + if(IE8_DOM_DEFINE)try { + return gOPD(O, P); + } catch(e){ /* empty */ } + if(has(O, P))return createDesc(!pIE.f.call(O, P), O[P]); +}; +},{"./_descriptors":93,"./_has":101,"./_ie8-dom-define":104,"./_object-pie":128,"./_property-desc":130,"./_to-iobject":141,"./_to-primitive":144}],122:[function(_dereq_,module,exports){ +// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window +var toIObject = _dereq_('./_to-iobject') + , gOPN = _dereq_('./_object-gopn').f + , toString = {}.toString; + +var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames + ? Object.getOwnPropertyNames(window) : []; + +var getWindowNames = function(it){ + try { + return gOPN(it); + } catch(e){ + return windowNames.slice(); + } +}; + +module.exports.f = function getOwnPropertyNames(it){ + return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it)); +}; + +},{"./_object-gopn":123,"./_to-iobject":141}],123:[function(_dereq_,module,exports){ +// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O) +var $keys = _dereq_('./_object-keys-internal') + , hiddenKeys = _dereq_('./_enum-bug-keys').concat('length', 'prototype'); + +exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O){ + return $keys(O, hiddenKeys); +}; +},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],124:[function(_dereq_,module,exports){ +exports.f = Object.getOwnPropertySymbols; +},{}],125:[function(_dereq_,module,exports){ +// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O) +var has = _dereq_('./_has') + , toObject = _dereq_('./_to-object') + , IE_PROTO = _dereq_('./_shared-key')('IE_PROTO') + , ObjectProto = Object.prototype; + +module.exports = Object.getPrototypeOf || function(O){ + O = toObject(O); + if(has(O, IE_PROTO))return O[IE_PROTO]; + if(typeof O.constructor == 'function' && O instanceof O.constructor){ + return O.constructor.prototype; + } return O instanceof Object ? ObjectProto : null; +}; +},{"./_has":101,"./_shared-key":136,"./_to-object":143}],126:[function(_dereq_,module,exports){ +var has = _dereq_('./_has') + , toIObject = _dereq_('./_to-iobject') + , arrayIndexOf = _dereq_('./_array-includes')(false) + , IE_PROTO = _dereq_('./_shared-key')('IE_PROTO'); + +module.exports = function(object, names){ + var O = toIObject(object) + , i = 0 + , result = [] + , key; + for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key); + // Don't enum bug & hidden keys + while(names.length > i)if(has(O, key = names[i++])){ + ~arrayIndexOf(result, key) || result.push(key); + } + return result; +}; +},{"./_array-includes":80,"./_has":101,"./_shared-key":136,"./_to-iobject":141}],127:[function(_dereq_,module,exports){ +// 19.1.2.14 / 15.2.3.14 Object.keys(O) +var $keys = _dereq_('./_object-keys-internal') + , enumBugKeys = _dereq_('./_enum-bug-keys'); + +module.exports = Object.keys || function keys(O){ + return $keys(O, enumBugKeys); +}; +},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],128:[function(_dereq_,module,exports){ +exports.f = {}.propertyIsEnumerable; +},{}],129:[function(_dereq_,module,exports){ +// most Object methods by ES6 should accept primitives +var $export = _dereq_('./_export') + , core = _dereq_('./_core') + , fails = _dereq_('./_fails'); +module.exports = function(KEY, exec){ + var fn = (core.Object || {})[KEY] || Object[KEY] + , exp = {}; + exp[KEY] = exec(fn); + $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); +}; +},{"./_core":90,"./_export":97,"./_fails":98}],130:[function(_dereq_,module,exports){ +module.exports = function(bitmap, value){ + return { + enumerable : !(bitmap & 1), + configurable: !(bitmap & 2), + writable : !(bitmap & 4), + value : value + }; +}; +},{}],131:[function(_dereq_,module,exports){ +var hide = _dereq_('./_hide'); +module.exports = function(target, src, safe){ + for(var key in src){ + if(safe && target[key])target[key] = src[key]; + else hide(target, key, src[key]); + } return target; +}; +},{"./_hide":102}],132:[function(_dereq_,module,exports){ +module.exports = _dereq_('./_hide'); +},{"./_hide":102}],133:[function(_dereq_,module,exports){ +// Works with __proto__ only. Old v8 can't work with null proto objects. +/* eslint-disable no-proto */ +var isObject = _dereq_('./_is-object') + , anObject = _dereq_('./_an-object'); +var check = function(O, proto){ + anObject(O); + if(!isObject(proto) && proto !== null)throw TypeError(proto + ": can't set as prototype!"); +}; +module.exports = { + set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line + function(test, buggy, set){ + try { + set = _dereq_('./_ctx')(Function.call, _dereq_('./_object-gopd').f(Object.prototype, '__proto__').set, 2); + set(test, []); + buggy = !(test instanceof Array); + } catch(e){ buggy = true; } + return function setPrototypeOf(O, proto){ + check(O, proto); + if(buggy)O.__proto__ = proto; + else set(O, proto); + return O; + }; + }({}, false) : undefined), + check: check +}; +},{"./_an-object":78,"./_ctx":91,"./_is-object":108,"./_object-gopd":121}],134:[function(_dereq_,module,exports){ +'use strict'; +var global = _dereq_('./_global') + , core = _dereq_('./_core') + , dP = _dereq_('./_object-dp') + , DESCRIPTORS = _dereq_('./_descriptors') + , SPECIES = _dereq_('./_wks')('species'); + +module.exports = function(KEY){ + var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY]; + if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, { + configurable: true, + get: function(){ return this; } + }); +}; +},{"./_core":90,"./_descriptors":93,"./_global":100,"./_object-dp":119,"./_wks":148}],135:[function(_dereq_,module,exports){ +var def = _dereq_('./_object-dp').f + , has = _dereq_('./_has') + , TAG = _dereq_('./_wks')('toStringTag'); + +module.exports = function(it, tag, stat){ + if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag}); +}; +},{"./_has":101,"./_object-dp":119,"./_wks":148}],136:[function(_dereq_,module,exports){ +var shared = _dereq_('./_shared')('keys') + , uid = _dereq_('./_uid'); +module.exports = function(key){ + return shared[key] || (shared[key] = uid(key)); +}; +},{"./_shared":137,"./_uid":145}],137:[function(_dereq_,module,exports){ +var global = _dereq_('./_global') + , SHARED = '__core-js_shared__' + , store = global[SHARED] || (global[SHARED] = {}); +module.exports = function(key){ + return store[key] || (store[key] = {}); +}; +},{"./_global":100}],138:[function(_dereq_,module,exports){ +var toInteger = _dereq_('./_to-integer') + , defined = _dereq_('./_defined'); +// true -> String#at +// false -> String#codePointAt +module.exports = function(TO_STRING){ + return function(that, pos){ + var s = String(defined(that)) + , i = toInteger(pos) + , l = s.length + , a, b; + if(i < 0 || i >= l)return TO_STRING ? '' : undefined; + a = s.charCodeAt(i); + return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff + ? TO_STRING ? s.charAt(i) : a + : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; + }; +}; +},{"./_defined":92,"./_to-integer":140}],139:[function(_dereq_,module,exports){ +var toInteger = _dereq_('./_to-integer') + , max = Math.max + , min = Math.min; +module.exports = function(index, length){ + index = toInteger(index); + return index < 0 ? max(index + length, 0) : min(index, length); +}; +},{"./_to-integer":140}],140:[function(_dereq_,module,exports){ +// 7.1.4 ToInteger +var ceil = Math.ceil + , floor = Math.floor; +module.exports = function(it){ + return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); +}; +},{}],141:[function(_dereq_,module,exports){ +// to indexed object, toObject with fallback for non-array-like ES3 strings +var IObject = _dereq_('./_iobject') + , defined = _dereq_('./_defined'); +module.exports = function(it){ + return IObject(defined(it)); +}; +},{"./_defined":92,"./_iobject":105}],142:[function(_dereq_,module,exports){ +// 7.1.15 ToLength +var toInteger = _dereq_('./_to-integer') + , min = Math.min; +module.exports = function(it){ + return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 +}; +},{"./_to-integer":140}],143:[function(_dereq_,module,exports){ +// 7.1.13 ToObject(argument) +var defined = _dereq_('./_defined'); +module.exports = function(it){ + return Object(defined(it)); +}; +},{"./_defined":92}],144:[function(_dereq_,module,exports){ +// 7.1.1 ToPrimitive(input [, PreferredType]) +var isObject = _dereq_('./_is-object'); +// instead of the ES6 spec version, we didn't implement @@toPrimitive case +// and the second argument - flag - preferred type is a string +module.exports = function(it, S){ + if(!isObject(it))return it; + var fn, val; + if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val; + if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val; + if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val; + throw TypeError("Can't convert object to primitive value"); +}; +},{"./_is-object":108}],145:[function(_dereq_,module,exports){ +var id = 0 + , px = Math.random(); +module.exports = function(key){ + return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); +}; +},{}],146:[function(_dereq_,module,exports){ +var global = _dereq_('./_global') + , core = _dereq_('./_core') + , LIBRARY = _dereq_('./_library') + , wksExt = _dereq_('./_wks-ext') + , defineProperty = _dereq_('./_object-dp').f; +module.exports = function(name){ + var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {}); + if(name.charAt(0) != '_' && !(name in $Symbol))defineProperty($Symbol, name, {value: wksExt.f(name)}); +}; +},{"./_core":90,"./_global":100,"./_library":115,"./_object-dp":119,"./_wks-ext":147}],147:[function(_dereq_,module,exports){ +exports.f = _dereq_('./_wks'); +},{"./_wks":148}],148:[function(_dereq_,module,exports){ +var store = _dereq_('./_shared')('wks') + , uid = _dereq_('./_uid') + , Symbol = _dereq_('./_global').Symbol + , USE_SYMBOL = typeof Symbol == 'function'; + +var $exports = module.exports = function(name){ + return store[name] || (store[name] = + USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); +}; + +$exports.store = store; +},{"./_global":100,"./_shared":137,"./_uid":145}],149:[function(_dereq_,module,exports){ +var classof = _dereq_('./_classof') + , ITERATOR = _dereq_('./_wks')('iterator') + , Iterators = _dereq_('./_iterators'); +module.exports = _dereq_('./_core').getIteratorMethod = function(it){ + if(it != undefined)return it[ITERATOR] + || it['@@iterator'] + || Iterators[classof(it)]; +}; +},{"./_classof":84,"./_core":90,"./_iterators":113,"./_wks":148}],150:[function(_dereq_,module,exports){ +var anObject = _dereq_('./_an-object') + , get = _dereq_('./core.get-iterator-method'); +module.exports = _dereq_('./_core').getIterator = function(it){ + var iterFn = get(it); + if(typeof iterFn != 'function')throw TypeError(it + ' is not iterable!'); + return anObject(iterFn.call(it)); +}; +},{"./_an-object":78,"./_core":90,"./core.get-iterator-method":149}],151:[function(_dereq_,module,exports){ +'use strict'; +var addToUnscopables = _dereq_('./_add-to-unscopables') + , step = _dereq_('./_iter-step') + , Iterators = _dereq_('./_iterators') + , toIObject = _dereq_('./_to-iobject'); + +// 22.1.3.4 Array.prototype.entries() +// 22.1.3.13 Array.prototype.keys() +// 22.1.3.29 Array.prototype.values() +// 22.1.3.30 Array.prototype[@@iterator]() +module.exports = _dereq_('./_iter-define')(Array, 'Array', function(iterated, kind){ + this._t = toIObject(iterated); // target + this._i = 0; // next index + this._k = kind; // kind +// 22.1.5.2.1 %ArrayIteratorPrototype%.next() +}, function(){ + var O = this._t + , kind = this._k + , index = this._i++; + if(!O || index >= O.length){ + this._t = undefined; + return step(1); + } + if(kind == 'keys' )return step(0, index); + if(kind == 'values')return step(0, O[index]); + return step(0, [index, O[index]]); +}, 'values'); + +// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7) +Iterators.Arguments = Iterators.Array; + +addToUnscopables('keys'); +addToUnscopables('values'); +addToUnscopables('entries'); +},{"./_add-to-unscopables":76,"./_iter-define":111,"./_iter-step":112,"./_iterators":113,"./_to-iobject":141}],152:[function(_dereq_,module,exports){ +'use strict'; +var strong = _dereq_('./_collection-strong'); + +// 23.1 Map Objects +module.exports = _dereq_('./_collection')('Map', function(get){ + return function Map(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); }; +}, { + // 23.1.3.6 Map.prototype.get(key) + get: function get(key){ + var entry = strong.getEntry(this, key); + return entry && entry.v; + }, + // 23.1.3.9 Map.prototype.set(key, value) + set: function set(key, value){ + return strong.def(this, key === 0 ? 0 : key, value); + } +}, strong, true); +},{"./_collection":89,"./_collection-strong":86}],153:[function(_dereq_,module,exports){ +var $export = _dereq_('./_export') +// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) +$export($export.S, 'Object', {create: _dereq_('./_object-create')}); +},{"./_export":97,"./_object-create":118}],154:[function(_dereq_,module,exports){ +var $export = _dereq_('./_export'); +// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes) +$export($export.S + $export.F * !_dereq_('./_descriptors'), 'Object', {defineProperty: _dereq_('./_object-dp').f}); +},{"./_descriptors":93,"./_export":97,"./_object-dp":119}],155:[function(_dereq_,module,exports){ +// 19.1.2.5 Object.freeze(O) +var isObject = _dereq_('./_is-object') + , meta = _dereq_('./_meta').onFreeze; + +_dereq_('./_object-sap')('freeze', function($freeze){ + return function freeze(it){ + return $freeze && isObject(it) ? $freeze(meta(it)) : it; + }; +}); +},{"./_is-object":108,"./_meta":116,"./_object-sap":129}],156:[function(_dereq_,module,exports){ +// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) +var toIObject = _dereq_('./_to-iobject') + , $getOwnPropertyDescriptor = _dereq_('./_object-gopd').f; + +_dereq_('./_object-sap')('getOwnPropertyDescriptor', function(){ + return function getOwnPropertyDescriptor(it, key){ + return $getOwnPropertyDescriptor(toIObject(it), key); + }; +}); +},{"./_object-gopd":121,"./_object-sap":129,"./_to-iobject":141}],157:[function(_dereq_,module,exports){ +// 19.1.2.9 Object.getPrototypeOf(O) +var toObject = _dereq_('./_to-object') + , $getPrototypeOf = _dereq_('./_object-gpo'); + +_dereq_('./_object-sap')('getPrototypeOf', function(){ + return function getPrototypeOf(it){ + return $getPrototypeOf(toObject(it)); + }; +}); +},{"./_object-gpo":125,"./_object-sap":129,"./_to-object":143}],158:[function(_dereq_,module,exports){ +// 19.1.2.14 Object.keys(O) +var toObject = _dereq_('./_to-object') + , $keys = _dereq_('./_object-keys'); + +_dereq_('./_object-sap')('keys', function(){ + return function keys(it){ + return $keys(toObject(it)); + }; +}); +},{"./_object-keys":127,"./_object-sap":129,"./_to-object":143}],159:[function(_dereq_,module,exports){ +// 19.1.3.19 Object.setPrototypeOf(O, proto) +var $export = _dereq_('./_export'); +$export($export.S, 'Object', {setPrototypeOf: _dereq_('./_set-proto').set}); +},{"./_export":97,"./_set-proto":133}],160:[function(_dereq_,module,exports){ + +},{}],161:[function(_dereq_,module,exports){ +'use strict'; +var $at = _dereq_('./_string-at')(true); + +// 21.1.3.27 String.prototype[@@iterator]() +_dereq_('./_iter-define')(String, 'String', function(iterated){ + this._t = String(iterated); // target + this._i = 0; // next index +// 21.1.5.2.1 %StringIteratorPrototype%.next() +}, function(){ + var O = this._t + , index = this._i + , point; + if(index >= O.length)return {value: undefined, done: true}; + point = $at(O, index); + this._i += point.length; + return {value: point, done: false}; +}); +},{"./_iter-define":111,"./_string-at":138}],162:[function(_dereq_,module,exports){ +'use strict'; +// ECMAScript 6 symbols shim +var global = _dereq_('./_global') + , has = _dereq_('./_has') + , DESCRIPTORS = _dereq_('./_descriptors') + , $export = _dereq_('./_export') + , redefine = _dereq_('./_redefine') + , META = _dereq_('./_meta').KEY + , $fails = _dereq_('./_fails') + , shared = _dereq_('./_shared') + , setToStringTag = _dereq_('./_set-to-string-tag') + , uid = _dereq_('./_uid') + , wks = _dereq_('./_wks') + , wksExt = _dereq_('./_wks-ext') + , wksDefine = _dereq_('./_wks-define') + , keyOf = _dereq_('./_keyof') + , enumKeys = _dereq_('./_enum-keys') + , isArray = _dereq_('./_is-array') + , anObject = _dereq_('./_an-object') + , toIObject = _dereq_('./_to-iobject') + , toPrimitive = _dereq_('./_to-primitive') + , createDesc = _dereq_('./_property-desc') + , _create = _dereq_('./_object-create') + , gOPNExt = _dereq_('./_object-gopn-ext') + , $GOPD = _dereq_('./_object-gopd') + , $DP = _dereq_('./_object-dp') + , $keys = _dereq_('./_object-keys') + , gOPD = $GOPD.f + , dP = $DP.f + , gOPN = gOPNExt.f + , $Symbol = global.Symbol + , $JSON = global.JSON + , _stringify = $JSON && $JSON.stringify + , PROTOTYPE = 'prototype' + , HIDDEN = wks('_hidden') + , TO_PRIMITIVE = wks('toPrimitive') + , isEnum = {}.propertyIsEnumerable + , SymbolRegistry = shared('symbol-registry') + , AllSymbols = shared('symbols') + , OPSymbols = shared('op-symbols') + , ObjectProto = Object[PROTOTYPE] + , USE_NATIVE = typeof $Symbol == 'function' + , QObject = global.QObject; +// Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173 +var setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild; + +// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687 +var setSymbolDesc = DESCRIPTORS && $fails(function(){ + return _create(dP({}, 'a', { + get: function(){ return dP(this, 'a', {value: 7}).a; } + })).a != 7; +}) ? function(it, key, D){ + var protoDesc = gOPD(ObjectProto, key); + if(protoDesc)delete ObjectProto[key]; + dP(it, key, D); + if(protoDesc && it !== ObjectProto)dP(ObjectProto, key, protoDesc); +} : dP; + +var wrap = function(tag){ + var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]); + sym._k = tag; + return sym; +}; + +var isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function(it){ + return typeof it == 'symbol'; +} : function(it){ + return it instanceof $Symbol; +}; + +var $defineProperty = function defineProperty(it, key, D){ + if(it === ObjectProto)$defineProperty(OPSymbols, key, D); + anObject(it); + key = toPrimitive(key, true); + anObject(D); + if(has(AllSymbols, key)){ + if(!D.enumerable){ + if(!has(it, HIDDEN))dP(it, HIDDEN, createDesc(1, {})); + it[HIDDEN][key] = true; + } else { + if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false; + D = _create(D, {enumerable: createDesc(0, false)}); + } return setSymbolDesc(it, key, D); + } return dP(it, key, D); +}; +var $defineProperties = function defineProperties(it, P){ + anObject(it); + var keys = enumKeys(P = toIObject(P)) + , i = 0 + , l = keys.length + , key; + while(l > i)$defineProperty(it, key = keys[i++], P[key]); + return it; +}; +var $create = function create(it, P){ + return P === undefined ? _create(it) : $defineProperties(_create(it), P); +}; +var $propertyIsEnumerable = function propertyIsEnumerable(key){ + var E = isEnum.call(this, key = toPrimitive(key, true)); + if(this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return false; + return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true; +}; +var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){ + it = toIObject(it); + key = toPrimitive(key, true); + if(it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return; + var D = gOPD(it, key); + if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true; + return D; +}; +var $getOwnPropertyNames = function getOwnPropertyNames(it){ + var names = gOPN(toIObject(it)) + , result = [] + , i = 0 + , key; + while(names.length > i){ + if(!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META)result.push(key); + } return result; +}; +var $getOwnPropertySymbols = function getOwnPropertySymbols(it){ + var IS_OP = it === ObjectProto + , names = gOPN(IS_OP ? OPSymbols : toIObject(it)) + , result = [] + , i = 0 + , key; + while(names.length > i){ + if(has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true))result.push(AllSymbols[key]); + } return result; +}; + +// 19.4.1.1 Symbol([description]) +if(!USE_NATIVE){ + $Symbol = function Symbol(){ + if(this instanceof $Symbol)throw TypeError('Symbol is not a constructor!'); + var tag = uid(arguments.length > 0 ? arguments[0] : undefined); + var $set = function(value){ + if(this === ObjectProto)$set.call(OPSymbols, value); + if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false; + setSymbolDesc(this, tag, createDesc(1, value)); + }; + if(DESCRIPTORS && setter)setSymbolDesc(ObjectProto, tag, {configurable: true, set: $set}); + return wrap(tag); + }; + redefine($Symbol[PROTOTYPE], 'toString', function toString(){ + return this._k; + }); + + $GOPD.f = $getOwnPropertyDescriptor; + $DP.f = $defineProperty; + _dereq_('./_object-gopn').f = gOPNExt.f = $getOwnPropertyNames; + _dereq_('./_object-pie').f = $propertyIsEnumerable; + _dereq_('./_object-gops').f = $getOwnPropertySymbols; + + if(DESCRIPTORS && !_dereq_('./_library')){ + redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true); + } + + wksExt.f = function(name){ + return wrap(wks(name)); + } +} + +$export($export.G + $export.W + $export.F * !USE_NATIVE, {Symbol: $Symbol}); + +for(var symbols = ( + // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14 + 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables' +).split(','), i = 0; symbols.length > i; )wks(symbols[i++]); + +for(var symbols = $keys(wks.store), i = 0; symbols.length > i; )wksDefine(symbols[i++]); + +$export($export.S + $export.F * !USE_NATIVE, 'Symbol', { + // 19.4.2.1 Symbol.for(key) + 'for': function(key){ + return has(SymbolRegistry, key += '') + ? SymbolRegistry[key] + : SymbolRegistry[key] = $Symbol(key); + }, + // 19.4.2.5 Symbol.keyFor(sym) + keyFor: function keyFor(key){ + if(isSymbol(key))return keyOf(SymbolRegistry, key); + throw TypeError(key + ' is not a symbol!'); + }, + useSetter: function(){ setter = true; }, + useSimple: function(){ setter = false; } +}); + +$export($export.S + $export.F * !USE_NATIVE, 'Object', { + // 19.1.2.2 Object.create(O [, Properties]) + create: $create, + // 19.1.2.4 Object.defineProperty(O, P, Attributes) + defineProperty: $defineProperty, + // 19.1.2.3 Object.defineProperties(O, Properties) + defineProperties: $defineProperties, + // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) + getOwnPropertyDescriptor: $getOwnPropertyDescriptor, + // 19.1.2.7 Object.getOwnPropertyNames(O) + getOwnPropertyNames: $getOwnPropertyNames, + // 19.1.2.8 Object.getOwnPropertySymbols(O) + getOwnPropertySymbols: $getOwnPropertySymbols +}); + +// 24.3.2 JSON.stringify(value [, replacer [, space]]) +$JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function(){ + var S = $Symbol(); + // MS Edge converts symbol values to JSON as {} + // WebKit converts symbol values to JSON as null + // V8 throws on boxed symbols + return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}'; +})), 'JSON', { + stringify: function stringify(it){ + if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined + var args = [it] + , i = 1 + , replacer, $replacer; + while(arguments.length > i)args.push(arguments[i++]); + replacer = args[1]; + if(typeof replacer == 'function')$replacer = replacer; + if($replacer || !isArray(replacer))replacer = function(key, value){ + if($replacer)value = $replacer.call(this, key, value); + if(!isSymbol(value))return value; + }; + args[1] = replacer; + return _stringify.apply($JSON, args); + } +}); + +// 19.4.3.4 Symbol.prototype[@@toPrimitive](hint) +$Symbol[PROTOTYPE][TO_PRIMITIVE] || _dereq_('./_hide')($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf); +// 19.4.3.5 Symbol.prototype[@@toStringTag] +setToStringTag($Symbol, 'Symbol'); +// 20.2.1.9 Math[@@toStringTag] +setToStringTag(Math, 'Math', true); +// 24.3.3 JSON[@@toStringTag] +setToStringTag(global.JSON, 'JSON', true); +},{"./_an-object":78,"./_descriptors":93,"./_enum-keys":96,"./_export":97,"./_fails":98,"./_global":100,"./_has":101,"./_hide":102,"./_is-array":107,"./_keyof":114,"./_library":115,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_object-gopd":121,"./_object-gopn":123,"./_object-gopn-ext":122,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_property-desc":130,"./_redefine":132,"./_set-to-string-tag":135,"./_shared":137,"./_to-iobject":141,"./_to-primitive":144,"./_uid":145,"./_wks":148,"./_wks-define":146,"./_wks-ext":147}],163:[function(_dereq_,module,exports){ +'use strict'; +var each = _dereq_('./_array-methods')(0) + , redefine = _dereq_('./_redefine') + , meta = _dereq_('./_meta') + , assign = _dereq_('./_object-assign') + , weak = _dereq_('./_collection-weak') + , isObject = _dereq_('./_is-object') + , getWeak = meta.getWeak + , isExtensible = Object.isExtensible + , uncaughtFrozenStore = weak.ufstore + , tmp = {} + , InternalMap; + +var wrapper = function(get){ + return function WeakMap(){ + return get(this, arguments.length > 0 ? arguments[0] : undefined); + }; +}; + +var methods = { + // 23.3.3.3 WeakMap.prototype.get(key) + get: function get(key){ + if(isObject(key)){ + var data = getWeak(key); + if(data === true)return uncaughtFrozenStore(this).get(key); + return data ? data[this._i] : undefined; + } + }, + // 23.3.3.5 WeakMap.prototype.set(key, value) + set: function set(key, value){ + return weak.def(this, key, value); + } +}; + +// 23.3 WeakMap Objects +var $WeakMap = module.exports = _dereq_('./_collection')('WeakMap', wrapper, methods, weak, true, true); + +// IE11 WeakMap frozen keys fix +if(new $WeakMap().set((Object.freeze || Object)(tmp), 7).get(tmp) != 7){ + InternalMap = weak.getConstructor(wrapper); + assign(InternalMap.prototype, methods); + meta.NEED = true; + each(['delete', 'has', 'get', 'set'], function(key){ + var proto = $WeakMap.prototype + , method = proto[key]; + redefine(proto, key, function(a, b){ + // store frozen objects on internal weakmap shim + if(isObject(a) && !isExtensible(a)){ + if(!this._f)this._f = new InternalMap; + var result = this._f[key](a, b); + return key == 'set' ? this : result; + // store all the rest on native weakmap + } return method.call(this, a, b); + }); + }); +} +},{"./_array-methods":81,"./_collection":89,"./_collection-weak":88,"./_is-object":108,"./_meta":116,"./_object-assign":117,"./_redefine":132}],164:[function(_dereq_,module,exports){ +// https://github.com/DavidBruant/Map-Set.prototype.toJSON +var $export = _dereq_('./_export'); + +$export($export.P + $export.R, 'Map', {toJSON: _dereq_('./_collection-to-json')('Map')}); +},{"./_collection-to-json":87,"./_export":97}],165:[function(_dereq_,module,exports){ +_dereq_('./_wks-define')('asyncIterator'); +},{"./_wks-define":146}],166:[function(_dereq_,module,exports){ +_dereq_('./_wks-define')('observable'); +},{"./_wks-define":146}],167:[function(_dereq_,module,exports){ +_dereq_('./es6.array.iterator'); +var global = _dereq_('./_global') + , hide = _dereq_('./_hide') + , Iterators = _dereq_('./_iterators') + , TO_STRING_TAG = _dereq_('./_wks')('toStringTag'); + +for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){ + var NAME = collections[i] + , Collection = global[NAME] + , proto = Collection && Collection.prototype; + if(proto && !proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME); + Iterators[NAME] = Iterators.Array; +} +},{"./_global":100,"./_hide":102,"./_iterators":113,"./_wks":148,"./es6.array.iterator":151}],168:[function(_dereq_,module,exports){ +arguments[4][160][0].apply(exports,arguments) +},{"dup":160}],169:[function(_dereq_,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +function EventEmitter() { + this._events = this._events || {}; + this._maxListeners = this._maxListeners || undefined; +} +module.exports = EventEmitter; + +// Backwards-compat with node 0.10.x +EventEmitter.EventEmitter = EventEmitter; + +EventEmitter.prototype._events = undefined; +EventEmitter.prototype._maxListeners = undefined; + +// By default EventEmitters will print a warning if more than 10 listeners are +// added to it. This is a useful default which helps finding memory leaks. +EventEmitter.defaultMaxListeners = 10; + +// Obviously not all Emitters should be limited to 10. This function allows +// that to be increased. Set to zero for unlimited. +EventEmitter.prototype.setMaxListeners = function(n) { + if (!isNumber(n) || n < 0 || isNaN(n)) + throw TypeError('n must be a positive number'); + this._maxListeners = n; + return this; +}; + +EventEmitter.prototype.emit = function(type) { + var er, handler, len, args, i, listeners; + + if (!this._events) + this._events = {}; + + // If there is no 'error' event listener then throw. + if (type === 'error') { + if (!this._events.error || + (isObject(this._events.error) && !this._events.error.length)) { + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } + throw TypeError('Uncaught, unspecified "error" event.'); + } + } + + handler = this._events[type]; + + if (isUndefined(handler)) + return false; + + if (isFunction(handler)) { + switch (arguments.length) { + // fast cases + case 1: + handler.call(this); + break; + case 2: + handler.call(this, arguments[1]); + break; + case 3: + handler.call(this, arguments[1], arguments[2]); + break; + // slower + default: + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + handler.apply(this, args); + } + } else if (isObject(handler)) { + len = arguments.length; + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + + listeners = handler.slice(); + len = listeners.length; + for (i = 0; i < len; i++) + listeners[i].apply(this, args); + } + + return true; +}; + +EventEmitter.prototype.addListener = function(type, listener) { + var m; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events) + this._events = {}; + + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (this._events.newListener) + this.emit('newListener', type, + isFunction(listener.listener) ? + listener.listener : listener); + + if (!this._events[type]) + // Optimize the case of one listener. Don't need the extra array object. + this._events[type] = listener; + else if (isObject(this._events[type])) + // If we've already got an array, just append. + this._events[type].push(listener); + else + // Adding the second element, need to change to array. + this._events[type] = [this._events[type], listener]; + + // Check for listener leak + if (isObject(this._events[type]) && !this._events[type].warned) { + var m; + if (!isUndefined(this._maxListeners)) { + m = this._maxListeners; + } else { + m = EventEmitter.defaultMaxListeners; + } + + if (m && m > 0 && this._events[type].length > m) { + this._events[type].warned = true; + console.error('(node) warning: possible EventEmitter memory ' + + 'leak detected. %d listeners added. ' + + 'Use emitter.setMaxListeners() to increase limit.', + this._events[type].length); + if (typeof console.trace === 'function') { + // not supported in IE 10 + console.trace(); + } + } + } + + return this; +}; + +EventEmitter.prototype.on = EventEmitter.prototype.addListener; + +EventEmitter.prototype.once = function(type, listener) { + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + var fired = false; + + function g() { + this.removeListener(type, g); + + if (!fired) { + fired = true; + listener.apply(this, arguments); + } + } + + g.listener = listener; + this.on(type, g); + + return this; +}; + +// emits a 'removeListener' event iff the listener was removed +EventEmitter.prototype.removeListener = function(type, listener) { + var list, position, length, i; + + if (!isFunction(listener)) + throw TypeError('listener must be a function'); + + if (!this._events || !this._events[type]) + return this; + + list = this._events[type]; + length = list.length; + position = -1; + + if (list === listener || + (isFunction(list.listener) && list.listener === listener)) { + delete this._events[type]; + if (this._events.removeListener) + this.emit('removeListener', type, listener); + + } else if (isObject(list)) { + for (i = length; i-- > 0;) { + if (list[i] === listener || + (list[i].listener && list[i].listener === listener)) { + position = i; + break; + } + } + + if (position < 0) + return this; + + if (list.length === 1) { + list.length = 0; + delete this._events[type]; + } else { + list.splice(position, 1); + } + + if (this._events.removeListener) + this.emit('removeListener', type, listener); + } + + return this; +}; + +EventEmitter.prototype.removeAllListeners = function(type) { + var key, listeners; + + if (!this._events) + return this; + + // not listening for removeListener, no need to emit + if (!this._events.removeListener) { + if (arguments.length === 0) + this._events = {}; + else if (this._events[type]) + delete this._events[type]; + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + for (key in this._events) { + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = {}; + return this; + } + + listeners = this._events[type]; + + if (isFunction(listeners)) { + this.removeListener(type, listeners); + } else { + // LIFO order + while (listeners.length) + this.removeListener(type, listeners[listeners.length - 1]); + } + delete this._events[type]; + + return this; +}; + +EventEmitter.prototype.listeners = function(type) { + var ret; + if (!this._events || !this._events[type]) + ret = []; + else if (isFunction(this._events[type])) + ret = [this._events[type]]; + else + ret = this._events[type].slice(); + return ret; +}; + +EventEmitter.listenerCount = function(emitter, type) { + var ret; + if (!emitter._events || !emitter._events[type]) + ret = 0; + else if (isFunction(emitter._events[type])) + ret = 1; + else + ret = emitter._events[type].length; + return ret; +}; + +function isFunction(arg) { + return typeof arg === 'function'; +} + +function isNumber(arg) { + return typeof arg === 'number'; +} + +function isObject(arg) { + return typeof arg === 'object' && arg !== null; +} + +function isUndefined(arg) { + return arg === void 0; +} + +},{}]},{},[10])(10) +}); \ No newline at end of file diff --git a/dist/parse.min.js b/dist/parse.min.js new file mode 100644 index 000000000..1e917b729 --- /dev/null +++ b/dist/parse.min.js @@ -0,0 +1,18 @@ +/** + * Parse JavaScript SDK v1.9.2 + * + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * The source tree of this library can be found at + * https://github.com/ParsePlatform/Parse-SDK-JS + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Parse=e()}}(function(){return function e(t,r,n){function o(i,s){if(!r[i]){if(!t[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(a)return a(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var c=r[i]={exports:{}};t[i][0].call(c.exports,function(e){var r=t[i][1][e];return o(r?r:e)},c,c.exports,e,t,r,n)}return r[i].exports}for(var a="function"==typeof require&&require,i=0;i>2&63),o(n<<4&48|a>>4&15),s?o(a<<2&60|i>>6&3):"=",u?o(63&i):"="].join("")}return t.join("")}}]),e}();r["default"]=h;var p={saveFile:function(e,t){if("file"!==t.format)throw new Error("saveFile can only be used with File-type sources.");var r={"X-Parse-Application-ID":c["default"].get("APPLICATION_ID"),"X-Parse-JavaScript-Key":c["default"].get("JAVASCRIPT_KEY"),"Content-Type":t.type||(t.file?t.file.type:null)},n=c["default"].get("SERVER_URL");return"/"!==n[n.length-1]&&(n+="/"),n+="files/"+e,c["default"].getRESTController().ajax("POST",n,t.file,r)},saveBase64:function(e,t){if("base64"!==t.format)throw new Error("saveBase64 can only be used with Base64-type sources.");var r={base64:t.base64};return t.type&&(r._ContentType=t.type),c["default"].getRESTController().request("POST","files/"+e,r)}};c["default"].setFileController(p)},{"./CoreManager":3,"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],15:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var o=e("babel-runtime/helpers/typeof"),a=n(o),i=e("babel-runtime/helpers/classCallCheck"),s=n(i),u=e("babel-runtime/helpers/createClass"),l=n(u),c=e("./ParsePromise"),f=n(c),d=function(){function e(t,r){(0,s["default"])(this,e),Array.isArray(t)?(e._validate(t[0],t[1]),this._latitude=t[0],this._longitude=t[1]):"object"===("undefined"==typeof t?"undefined":(0,a["default"])(t))?(e._validate(t.latitude,t.longitude),this._latitude=t.latitude,this._longitude=t.longitude):"number"==typeof t&&"number"==typeof r?(e._validate(t,r),this._latitude=t,this._longitude=r):(this._latitude=0,this._longitude=0)}return(0,l["default"])(e,[{key:"toJSON",value:function(){return e._validate(this._latitude,this._longitude),{__type:"GeoPoint",latitude:this._latitude,longitude:this._longitude}}},{key:"equals",value:function(t){return t instanceof e&&this.latitude===t.latitude&&this.longitude===t.longitude}},{key:"radiansTo",value:function(e){var t=Math.PI/180,r=this.latitude*t,n=this.longitude*t,o=e.latitude*t,a=e.longitude*t,i=Math.sin((r-o)/2),s=Math.sin((n-a)/2),u=i*i+Math.cos(r)*Math.cos(o)*s*s;return u=Math.min(1,u),2*Math.asin(Math.sqrt(u))}},{key:"kilometersTo",value:function(e){return 6371*this.radiansTo(e)}},{key:"milesTo",value:function(e){return 3958.8*this.radiansTo(e)}},{key:"latitude",get:function(){return this._latitude},set:function(t){e._validate(t,this.longitude),this._latitude=t}},{key:"longitude",get:function(){return this._longitude},set:function(t){e._validate(this.latitude,t),this._longitude=t}}],[{key:"_validate",value:function(e,t){if(e!==e||t!==t)throw new TypeError("GeoPoint latitude and longitude must be valid numbers");if(e<-90)throw new TypeError("GeoPoint latitude out of bounds: "+e+" < -90.0.");if(e>90)throw new TypeError("GeoPoint latitude out of bounds: "+e+" > 90.0.");if(t<-180)throw new TypeError("GeoPoint longitude out of bounds: "+t+" < -180.0.");if(t>180)throw new TypeError("GeoPoint longitude out of bounds: "+t+" > 180.0.")}},{key:"current",value:function(t){var r=new f["default"];return navigator.geolocation.getCurrentPosition(function(t){r.resolve(new e(t.coords.latitude,t.coords.longitude))},function(e){r.reject(e)}),r._thenRunCallbacks(t)}}]),e}();r["default"]=d},{"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],16:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var o=e("babel-runtime/helpers/typeof"),a=n(o),i=e("babel-runtime/core-js/object/get-prototype-of"),s=n(i),u=e("babel-runtime/helpers/classCallCheck"),l=n(u),c=e("babel-runtime/helpers/possibleConstructorReturn"),f=n(c),d=e("babel-runtime/helpers/inherits"),h=n(d),p=e("./ParseObject"),_=n(p),v=function(e){function t(e){(0,l["default"])(this,t);var r=(0,f["default"])(this,(t.__proto__||(0,s["default"])(t)).call(this,"_Installation"));if(e&&"object"===("undefined"==typeof e?"undefined":(0,a["default"])(e))&&!r.set(e||{}))throw new Error("Can't create an invalid Session");return r}return(0,h["default"])(t,e),t}(_["default"]);r["default"]=v,_["default"].registerSubclass("_Installation",v)},{"./ParseObject":18,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],17:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(){var e=h["default"].getLiveQueryController();e.open()}function a(){var e=h["default"].getLiveQueryController();e.close()}function i(){var e=h["default"].getUserController();return e.currentUserAsync().then(function(e){return e?e.getSessionToken():void 0})}function s(){return h["default"].getLiveQueryController().getDefaultLiveQueryClient()}Object.defineProperty(r,"__esModule",{value:!0});var u=e("./EventEmitter"),l=n(u),c=e("./LiveQueryClient"),f=n(c),d=e("./CoreManager"),h=n(d),p=e("./ParsePromise"),_=n(p),v=new l["default"];v.open=o,v.close=a,v.on("error",function(){}),r["default"]=v;var y=void 0,b={setDefaultLiveQueryClient:function(e){y=e},getDefaultLiveQueryClient:function(){return y?_["default"].as(y):i().then(function(e){var t=h["default"].get("LIVEQUERY_SERVER_URL");if(t&&0!==t.indexOf("ws"))throw new Error("You need to set a proper Parse LiveQuery server url before using LiveQueryClient");if(!t){var r=h["default"].get("SERVER_URL"),n="ws://";0===r.indexOf("https")&&(n="wss://");var o=r.replace(/^https?:\/\//,"");t=n+o,h["default"].set("LIVEQUERY_SERVER_URL",t)}var a=h["default"].get("APPLICATION_ID"),i=h["default"].get("JAVASCRIPT_KEY"),s=h["default"].get("MASTER_KEY");return y=new f["default"]({applicationId:a,serverURL:t,javascriptKey:i,masterKey:s,sessionToken:e}),y.on("error",function(e){v.emit("error",e)}),y.on("open",function(){v.emit("open")}),y.on("close",function(){v.emit("close")}),y})},open:function(){var e=this;s().then(function(t){e.resolve(t.open())})},close:function(){var e=this;s().then(function(t){e.resolve(t.close())})},subscribe:function(e){var t=this,r=new l["default"];return s().then(function(n){n.shouldOpen()&&n.open();var o=i();return o.then(function(o){var a=n.subscribe(e,o);r.id=a.id,r.query=a.query,r.sessionToken=a.sessionToken,r.unsubscribe=a.unsubscribe,a.on("open",function(){r.emit("open")}),a.on("create",function(e){r.emit("create",e)}),a.on("update",function(e){r.emit("update",e)}),a.on("enter",function(e){r.emit("enter",e)}),a.on("leave",function(e){r.emit("leave",e)}),a.on("delete",function(e){r.emit("delete",e)}),t.resolve()})}),r},unsubscribe:function(e){var t=this;s().then(function(r){t.resolve(r.unsubscribe(e))})},_clearCachedDefaultClient:function(){y=null}};h["default"].setLiveQueryController(b)},{"./CoreManager":3,"./EventEmitter":4,"./LiveQueryClient":7,"./ParsePromise":20}],18:[function(e,t,r){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t["default"]=e,t}function o(e){return e&&e.__esModule?e:{"default":e}}function a(){var e=k["default"].get("SERVER_URL");"/"!==e[e.length-1]&&(e+="/");var t=e.replace(/https?:\/\//,"");return t.substr(t.indexOf("/"))}Object.defineProperty(r,"__esModule",{value:!0});var i=e("babel-runtime/core-js/object/define-property"),s=o(i),u=e("babel-runtime/core-js/object/create"),l=o(u),c=e("babel-runtime/core-js/object/freeze"),f=o(c),d=e("babel-runtime/core-js/json/stringify"),h=o(d),p=e("babel-runtime/core-js/object/keys"),_=o(p),v=e("babel-runtime/helpers/typeof"),y=o(v),b=e("babel-runtime/helpers/classCallCheck"),g=o(b),m=e("babel-runtime/helpers/createClass"),C=o(m),j=e("./CoreManager"),k=o(j),O=e("./canBeSerialized"),w=o(O),S=e("./decode"),E=o(S),P=e("./encode"),A=o(P),I=e("./equals"),T=(o(I),e("./escape")),N=o(T),R=e("./ParseACL"),M=o(R),x=e("./parseDate"),D=o(x),L=e("./ParseError"),U=o(L),F=e("./ParseFile"),K=o(F),q=e("./ParseOp"),J=e("./ParsePromise"),W=o(J),Q=e("./ParseQuery"),B=o(Q),V=e("./ParseRelation"),G=o(V),z=e("./SingleInstanceStateController"),Y=n(z),H=e("./unique"),$=o(H),X=e("./UniqueInstanceStateController"),Z=n(X),ee=e("./unsavedChildren"),te=o(ee),re={},ne=0,oe=0,ae=!k["default"].get("IS_NODE");ae?k["default"].setObjectStateController(Y):k["default"].setObjectStateController(Z);var ie=function(){function e(t,r,n){(0,g["default"])(this,e),"function"==typeof this.initialize&&this.initialize.apply(this,arguments);var o=null;if(this._objCount=oe++,"string"==typeof t)this.className=t,r&&"object"===("undefined"==typeof r?"undefined":(0,y["default"])(r))&&(o=r);else if(t&&"object"===("undefined"==typeof t?"undefined":(0,y["default"])(t))){this.className=t.className,o={};for(var a in t)"className"!==a&&(o[a]=t[a]);r&&"object"===("undefined"==typeof r?"undefined":(0,y["default"])(r))&&(n=r)}if(o&&!this.set(o,n))throw new Error("Can't create an invalid Parse Object")}return(0,C["default"])(e,[{key:"_getId",value:function(){if("string"==typeof this.id)return this.id;if("string"==typeof this._localId)return this._localId;var e="local"+String(ne++);return this._localId=e,e}},{key:"_getStateIdentifier",value:function(){if(ae){var e=this.id;return e||(e=this._getId()),{id:e,className:this.className}}return this}},{key:"_getServerData",value:function(){var e=k["default"].getObjectStateController();return e.getServerData(this._getStateIdentifier())}},{key:"_clearServerData",value:function(){var e=this._getServerData(),t={};for(var r in e)t[r]=void 0;var n=k["default"].getObjectStateController();n.setServerData(this._getStateIdentifier(),t)}},{key:"_getPendingOps",value:function(){var e=k["default"].getObjectStateController();return e.getPendingOps(this._getStateIdentifier())}},{key:"_clearPendingOps",value:function(){var e=this._getPendingOps(),t=e[e.length-1],r=(0,_["default"])(t);r.forEach(function(e){delete t[e]})}},{key:"_getDirtyObjectAttributes",value:function(){var t=this.attributes,r=k["default"].getObjectStateController(),n=r.getObjectCache(this._getStateIdentifier()),o={};for(var a in t){var i=t[a];if(i&&"object"===("undefined"==typeof i?"undefined":(0,y["default"])(i))&&!(i instanceof e)&&!(i instanceof K["default"])&&!(i instanceof G["default"]))try{var s=(0,A["default"])(i,!1,!0),u=(0,h["default"])(s);n[a]!==u&&(o[a]=i)}catch(l){o[a]=i}}return o}},{key:"_toFullJSON",value:function(e){var t=this.toJSON(e);return t.__type="Object",t.className=this.className,t}},{key:"_getSaveJSON",value:function(){var e=this._getPendingOps(),t=this._getDirtyObjectAttributes(),r={};for(var n in t)r[n]=new q.SetOp(t[n]).toJSON();for(n in e[0])r[n]=e[0][n].toJSON();return r}},{key:"_getSaveParams",value:function(){var e=this.id?"PUT":"POST",t=this._getSaveJSON(),r="classes/"+this.className;return this.id?r+="/"+this.id:"_User"===this.className&&(r="users"),{method:e,body:t,path:r}}},{key:"_finishFetch",value:function(e){!this.id&&e.objectId&&(this.id=e.objectId);var t=k["default"].getObjectStateController();t.initializeState(this._getStateIdentifier());var r={};for(var n in e)"ACL"===n?r[n]=new M["default"](e[n]):"objectId"!==n&&(r[n]=(0,E["default"])(e[n]),r[n]instanceof G["default"]&&r[n]._ensureParentAndKey(this,n));r.createdAt&&"string"==typeof r.createdAt&&(r.createdAt=(0,D["default"])(r.createdAt)),r.updatedAt&&"string"==typeof r.updatedAt&&(r.updatedAt=(0,D["default"])(r.updatedAt)),!r.updatedAt&&r.createdAt&&(r.updatedAt=r.createdAt),t.commitServerChanges(this._getStateIdentifier(),r)}},{key:"_setExisted",value:function(e){var t=k["default"].getObjectStateController(),r=t.getState(this._getStateIdentifier());r&&(r.existed=e)}},{key:"_migrateId",value:function(e){if(this._localId&&e)if(ae){var t=k["default"].getObjectStateController(),r=t.removeState(this._getStateIdentifier());this.id=e,delete this._localId,r&&t.initializeState(this._getStateIdentifier(),r)}else this.id=e,delete this._localId}},{key:"_handleSaveResponse",value:function(e,t){var r={},n=k["default"].getObjectStateController(),o=n.popPendingState(this._getStateIdentifier());for(var a in o)o[a]instanceof q.RelationOp?r[a]=o[a].applyTo(void 0,this,a):a in e||(r[a]=o[a].applyTo(void 0));for(a in e)"createdAt"!==a&&"updatedAt"!==a||"string"!=typeof e[a]?"ACL"===a?r[a]=new M["default"](e[a]):"objectId"!==a&&(r[a]=(0,E["default"])(e[a]),r[a]instanceof q.UnsetOp&&(r[a]=void 0)):r[a]=(0,D["default"])(e[a]);r.createdAt&&!r.updatedAt&&(r.updatedAt=r.createdAt),this._migrateId(e.objectId),201!==t&&this._setExisted(!0),n.commitServerChanges(this._getStateIdentifier(),r)}},{key:"_handleSaveError",value:function(){this._getPendingOps();var e=k["default"].getObjectStateController();e.mergeFirstPendingState(this._getStateIdentifier())}},{key:"initialize",value:function(){}},{key:"toJSON",value:function(e){var t=this.id?this.className+":"+this.id:this,e=e||[t],r={},n=this.attributes;for(var o in n)"createdAt"!==o&&"updatedAt"!==o||!n[o].toJSON?r[o]=(0,A["default"])(n[o],!1,!1,e):r[o]=n[o].toJSON();var a=this._getPendingOps();for(var o in a[0])r[o]=a[0][o].toJSON();return this.id&&(r.objectId=this.id),r}},{key:"equals",value:function(t){return this===t||t instanceof e&&this.className===t.className&&this.id===t.id&&"undefined"!=typeof this.id}},{key:"dirty",value:function(e){if(!this.id)return!0;var t=this._getPendingOps(),r=this._getDirtyObjectAttributes();if(e){if(r.hasOwnProperty(e))return!0;for(var n=0;n-1)throw new Error("Cannot modify readonly attribute: "+i);r.unset?o[i]=new q.UnsetOp:n[i]instanceof q.Op?o[i]=n[i]:n[i]&&"object"===(0,y["default"])(n[i])&&"string"==typeof n[i].__op?o[i]=(0,q.opFromJSON)(n[i]):"objectId"===i||"id"===i?"string"==typeof n[i]&&(this.id=n[i]):"ACL"!==i||"object"!==(0,y["default"])(n[i])||n[i]instanceof M["default"]?o[i]=new q.SetOp(n[i]):o[i]=new q.SetOp(new M["default"](n[i]))}var s=this.attributes,u={};for(var l in o)o[l]instanceof q.RelationOp?u[l]=o[l].applyTo(s[l],this,l):o[l]instanceof q.UnsetOp||(u[l]=o[l].applyTo(s[l]));if(!r.ignoreValidation){var c=this.validate(u);if(c)return"function"==typeof r.error&&r.error(this,c),!1}var f=this._getPendingOps(),d=f.length-1,h=k["default"].getObjectStateController();for(var l in o){var p=o[l].mergeWith(f[d][l]);h.setPendingOp(this._getStateIdentifier(),l,p)}return this}},{key:"unset",value:function(e,t){return t=t||{},t.unset=!0,this.set(e,null,t)}},{key:"increment",value:function(e,t){if("undefined"==typeof t&&(t=1),"number"!=typeof t)throw new Error("Cannot increment by a non-numeric amount.");return this.set(e,new q.IncrementOp(t))}},{key:"add",value:function(e,t){return this.set(e,new q.AddOp([t]))}},{key:"addUnique",value:function(e,t){return this.set(e,new q.AddUniqueOp([t]))}},{key:"remove",value:function(e,t){return this.set(e,new q.RemoveOp([t]))}},{key:"op",value:function(e){for(var t=this._getPendingOps(),r=t.length;r--;)if(t[r][e])return t[r][e]}},{key:"clone",value:function(){var e=new this.constructor;e.className||(e.className=this.className);var t=this.attributes;if("function"==typeof this.constructor.readOnlyAttributes){var r=this.constructor.readOnlyAttributes()||[],n={};for(var o in t)r.indexOf(o)<0&&(n[o]=t[o]);t=n}return e.set&&e.set(t),e}},{key:"newInstance",value:function(){var e=new this.constructor;if(e.className||(e.className=this.className),e.id=this.id,ae)return e;var t=k["default"].getObjectStateController();return t&&t.duplicateState(this._getStateIdentifier(),e._getStateIdentifier()),e}},{key:"isNew",value:function(){return!this.id}},{key:"existed",value:function(){if(!this.id)return!1;var e=k["default"].getObjectStateController(),t=e.getState(this._getStateIdentifier());return!!t&&t.existed}},{key:"isValid",value:function(){return!this.validate(this.attributes)}},{key:"validate",value:function(e){if(e.hasOwnProperty("ACL")&&!(e.ACL instanceof M["default"]))return new U["default"](U["default"].OTHER_CAUSE,"ACL must be a Parse ACL.");for(var t in e)if(!/^[A-Za-z][0-9A-Za-z_]*$/.test(t))return new U["default"](U["default"].INVALID_KEY_NAME);return!1}},{key:"getACL",value:function(){var e=this.get("ACL");return e instanceof M["default"]?e:null}},{key:"setACL",value:function(e,t){return this.set("ACL",e,t)}},{key:"revert",value:function(){this._clearPendingOps()}},{key:"clear",value:function(){var e=this.attributes,t={},r=["createdAt","updatedAt"];"function"==typeof this.constructor.readOnlyAttributes&&(r=r.concat(this.constructor.readOnlyAttributes()));for(var n in e)r.indexOf(n)<0&&(t[n]=!0);return this.set(t,{unset:!0})}},{key:"fetch",value:function(e){e=e||{};var t={};e.hasOwnProperty("useMasterKey")&&(t.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(t.sessionToken=e.sessionToken);var r=k["default"].getObjectController();return r.fetch(this,!0,t)._thenRunCallbacks(e)}},{key:"save",value:function(e,t,r){var n,o,a=this;if("object"===("undefined"==typeof e?"undefined":(0,y["default"])(e))||"undefined"==typeof e?(n=e,"object"===("undefined"==typeof t?"undefined":(0,y["default"])(t))&&(o=t)):(n={},n[e]=t,o=r),!o&&n&&(o={},"function"==typeof n.success&&(o.success=n.success,delete n.success),"function"==typeof n.error&&(o.error=n.error,delete n.error)),n){var i=this.validate(n);if(i)return o&&"function"==typeof o.error&&o.error(this,i),W["default"].error(i);this.set(n,o)}o=o||{};var s={};o.hasOwnProperty("useMasterKey")&&(s.useMasterKey=!!o.useMasterKey),o.hasOwnProperty("sessionToken")&&"string"==typeof o.sessionToken&&(s.sessionToken=o.sessionToken);var u=k["default"].getObjectController(),l=(0,te["default"])(this);return u.save(l,s).then(function(){return u.save(a,s)})._thenRunCallbacks(o,this)}},{key:"destroy",value:function(e){e=e||{};var t={};return e.hasOwnProperty("useMasterKey")&&(t.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(t.sessionToken=e.sessionToken),this.id?k["default"].getObjectController().destroy(this,t)._thenRunCallbacks(e):W["default"].as()._thenRunCallbacks(e)}},{key:"attributes",get:function(){var e=k["default"].getObjectStateController();return(0,f["default"])(e.estimateAttributes(this._getStateIdentifier()))}},{key:"createdAt",get:function(){return this._getServerData().createdAt}},{key:"updatedAt",get:function(){return this._getServerData().updatedAt}}],[{key:"_clearAllState",value:function(){var e=k["default"].getObjectStateController();e.clearAllState()}},{key:"fetchAll",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().fetch(e,!0,r)._thenRunCallbacks(t)}},{key:"fetchAllIfNeeded",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().fetch(e,!1,r)._thenRunCallbacks(t)}},{key:"destroyAll",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().destroy(e,r)._thenRunCallbacks(t)}},{key:"saveAll",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().save(e,r)._thenRunCallbacks(t)}},{key:"createWithoutData",value:function(e){var t=new this;return t.id=e,t}},{key:"fromJSON",value:function(t,r){if(!t.className)throw new Error("Cannot create an object without a className");var n=re[t.className],o=n?new n:new e(t.className),a={};for(var i in t)"className"!==i&&"__type"!==i&&(a[i]=t[i]);if(r){a.objectId&&(o.id=a.objectId);var s=null;"function"==typeof o._preserveFieldsOnFetch&&(s=o._preserveFieldsOnFetch()),o._clearServerData(),s&&o._finishFetch(s)}return o._finishFetch(a),t.objectId&&o._setExisted(!0),o}},{key:"registerSubclass",value:function(e,t){if("string"!=typeof e)throw new TypeError("The first argument must be a valid class name.");if("undefined"==typeof t)throw new TypeError("You must supply a subclass constructor.");if("function"!=typeof t)throw new TypeError("You must register the subclass constructor. Did you attempt to register an instance of the subclass?");re[e]=t,t.className||(t.className=e)}},{key:"extend",value:function(t,r,n){if("string"!=typeof t){if(t&&"string"==typeof t.className)return e.extend(t.className,t,r);throw new Error("Parse.Object.extend's first argument should be the className.")}var o=t;"User"===o&&k["default"].get("PERFORM_USER_REWRITE")&&(o="_User");var a=e.prototype;this.hasOwnProperty("__super__")&&this.__super__?a=this.prototype:re[o]&&(a=re[o].prototype);var i=function(e,t){if(this.className=o,this._objCount=oe++,"function"==typeof this.initialize&&this.initialize.apply(this,arguments),e&&"object"===("undefined"==typeof e?"undefined":(0,y["default"])(e))&&!this.set(e||{},t))throw new Error("Can't create an invalid Parse Object")};if(i.className=o,i.__super__=a,i.prototype=(0,l["default"])(a,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),r)for(var u in r)"className"!==u&&(0,s["default"])(i.prototype,u,{value:r[u],enumerable:!1,writable:!0,configurable:!0});if(n)for(var u in n)"className"!==u&&(0,s["default"])(i,u,{value:n[u],enumerable:!1,writable:!0,configurable:!0});return i.extend=function(t,r,n){return"string"==typeof t?e.extend.call(i,t,r,n):e.extend.call(i,o,t,r)},i.createWithoutData=e.createWithoutData,re[o]=i,i}},{key:"enableSingleInstance",value:function(){ae=!0,k["default"].setObjectStateController(Y)}},{key:"disableSingleInstance",value:function(){ae=!1,k["default"].setObjectStateController(Z)}}]),e}();r["default"]=ie;var se={fetch:function(e,t,r){if(Array.isArray(e)){if(e.length<1)return W["default"].as([]);var n=[],o=[],a=null,i=[],s=null;if(e.forEach(function(e,r){s||(a||(a=e.className),a!==e.className&&(s=new U["default"](U["default"].INVALID_CLASS_NAME,"All objects should be of the same class")),e.id||(s=new U["default"](U["default"].MISSING_OBJECT_ID,"All objects must have an ID")),(t||0===(0,_["default"])(e._getServerData()).length)&&(o.push(e.id),n.push(e)),i.push(e))}),s)return W["default"].error(s);var u=new B["default"](a);return u.containedIn("objectId",o),u._limit=o.length,u.find(r).then(function(e){var r={};e.forEach(function(e){r[e.id]=e});for(var o=0;o=20&&n.push([]))}),0===n[n.length-1].length&&n.pop();var o=W["default"].as(),i=[];return n.forEach(function(e){o=o.then(function(){return r.request("POST","batch",{requests:e.map(function(e){return{method:"DELETE",path:a()+"classes/"+e.className+"/"+e._getId(),body:{}}})},t).then(function(t){for(var r=0;r0},function(){var e=[],i=[];if(u.forEach(function(t){e.length<20&&(0,w["default"])(t)?e.push(t):i.push(t)}),u=i,e.length<1)return W["default"].error(new U["default"](U["default"].OTHER_CAUSE,"Tried to save a batch with a cycle."));var s=new W["default"],l=[],c=[];return e.forEach(function(e,t){var r=new W["default"];l.push(r),n.pushPendingState(e._getStateIdentifier()),c.push(n.enqueueTask(e._getStateIdentifier(),function(){return r.resolve(),s.then(function(r,n){if(r[t].hasOwnProperty("success"))e._handleSaveResponse(r[t].success,n);else{if(!o&&r[t].hasOwnProperty("error")){var a=r[t].error;o=new U["default"](a.code,a.error),u=[]}e._handleSaveError()}})}))}),W["default"].when(l).then(function(){return r.request("POST","batch",{requests:e.map(function(e){var t=e._getSaveParams();return t.path=a()+t.path,t})},t)}).then(function(e,t,r){s.resolve(e,t)}),W["default"].when(c)}).then(function(){return o?W["default"].error(o):W["default"].as(e)})})}if(e instanceof ie){var l=e,c=function(){var e=l._getSaveParams();return r.request(e.method,e.path,e.body,t).then(function(e,t){l._handleSaveResponse(e,t)},function(e){return l._handleSaveError(),W["default"].error(e)})};return n.pushPendingState(e._getStateIdentifier()),n.enqueueTask(e._getStateIdentifier(),c).then(function(){return e},function(e){return W["default"].error(e)})}return W["default"].as()}};k["default"].setObjectController(se)},{"./CoreManager":3,"./ParseACL":11,"./ParseError":13,"./ParseFile":14,"./ParseOp":19,"./ParsePromise":20,"./ParseQuery":21,"./ParseRelation":22,"./SingleInstanceStateController":28,"./UniqueInstanceStateController":32,"./canBeSerialized":34,"./decode":35,"./encode":36,"./equals":37,"./escape":38,"./parseDate":40,"./unique":41,"./unsavedChildren":42,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/object/create":46,"babel-runtime/core-js/object/define-property":47,"babel-runtime/core-js/object/freeze":48,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],19:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e){if(!e||!e.__op)return null;switch(e.__op){case"Delete":return new A;case"Increment":return new I(e.amount);case"Add":return new T((0,b["default"])(e.objects));case"AddUnique":return new N((0,b["default"])(e.objects));case"Remove":return new R((0,b["default"])(e.objects));case"AddRelation":var t=(0,b["default"])(e.objects);return Array.isArray(t)?new M(t,[]):new M([],[]);case"RemoveRelation":var r=(0,b["default"])(e.objects);return Array.isArray(r)?new M([],r):new M([],[]);case"Batch":for(var t=[],r=[],n=0;n-1;)r.splice(n,1),n=r.indexOf(this._value[t]);if(this._value[t]instanceof j["default"]&&this._value[t].id)for(var o=0;o-1&&r.splice(t,1)}),this.relationsToAdd.forEach(function(e){var t=r.indexOf(e);t<0&&r.push(e)});var n=e.relationsToRemove.concat([]);this.relationsToAdd.forEach(function(e){var t=n.indexOf(e);t>-1&&n.splice(t,1)}),this.relationsToRemove.forEach(function(e){var t=n.indexOf(e);t<0&&n.push(e)});var o=new t(r,n);return o._targetClassName=this._targetClassName,o}throw new Error("Cannot merge Relation Op with the previous Op")}},{key:"toJSON",value:function(){var e=this,t=function(t){return{__type:"Pointer",className:e._targetClassName,objectId:t}},r=null,n=null,o=null;return this.relationsToAdd.length>0&&(o=this.relationsToAdd.map(t),r={__op:"AddRelation",objects:o}),this.relationsToRemove.length>0&&(o=this.relationsToRemove.map(t),n={__op:"RemoveRelation",objects:o}),r&&n?{__op:"Batch",ops:[r,n]}:r||n||{}}}]),t}(E)},{"./ParseObject":18,"./ParseRelation":22,"./arrayContainsObject":33,"./decode":35,"./encode":36,"./unique":41,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],20:[function(e,t,r){(function(t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var o=e("babel-runtime/core-js/get-iterator"),a=n(o),i=e("babel-runtime/helpers/typeof"),s=n(i),u=e("babel-runtime/helpers/classCallCheck"),l=n(u),c=e("babel-runtime/helpers/createClass"),f=n(c),d=!0,h=function(){function e(t){(0,l["default"])(this,e),this._resolved=!1,this._rejected=!1,this._resolvedCallbacks=[],this._rejectedCallbacks=[],"function"==typeof t&&t(this.resolve.bind(this),this.reject.bind(this))}return(0,f["default"])(e,[{key:"resolve",value:function(){if(this._resolved||this._rejected)throw new Error("A promise was resolved even though it had already been "+(this._resolved?"resolved":"rejected")+".");this._resolved=!0;for(var e=arguments.length,t=Array(e),r=0;r=r&&h.resolve(_)))},function(e){h.reject(e),d=!0}):(_[n]=t,p++,!d&&p>=r&&h.resolve(_))}),h}},{key:"race",value:function(t){var r=!1,n=new e,o=!0,i=!1,s=void 0;try{for(var u,l=(0,a["default"])(t);!(o=(u=l.next()).done);o=!0){var c=u.value;e.is(c)?c.then(function(e){r||(r=!0,n.resolve(e))},function(e){r||(r=!0,n.reject(e))}):r||(r=!0,n.resolve(c))}}catch(f){i=!0,s=f}finally{try{!o&&l["return"]&&l["return"]()}finally{if(i)throw s}}return n}},{key:"_continueWhile",value:function(t,r){return t()?r().then(function(){return e._continueWhile(t,r)}):e.as()}},{key:"isPromisesAPlusCompliant",value:function(){return d}},{key:"enableAPlusCompliant",value:function(){d=!0}},{key:"disableAPlusCompliant",value:function(){d=!1}}]),e}();r["default"]=h}).call(this,e("_process"))},{_process:168,"babel-runtime/core-js/get-iterator":43,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],21:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e){return"\\Q"+e.replace("\\E","\\E\\\\E\\Q")+"\\E"}function a(e,t){var r={};if(t.forEach(function(t){var n=t.indexOf(".")!==-1;if(n||e.hasOwnProperty(t)){if(n){var o=t.split("."),a=e,i=r;o.forEach(function(e,t,r){a[e]||(a[e]=t==r.length-1?void 0:{}),a=a[e],t0){var n=function a(e,t,r,n){if(n)for(var o in e)e.hasOwnProperty(o)&&!t.hasOwnProperty(o)&&(t[o]=e[o]);for(var o in r)a(e[o],t[o],r[o],!0)},o=_["default"].getObjectStateController().getServerData({id:e.objectId,className:e.className});n(o,e,r,!1)}}Object.defineProperty(r,"__esModule",{value:!0});var i=e("babel-runtime/helpers/typeof"),s=n(i),u=e("babel-runtime/helpers/classCallCheck"),l=n(u),c=e("babel-runtime/helpers/createClass"),f=n(c),d=e("babel-runtime/core-js/object/keys"),h=n(d),p=e("./CoreManager"),_=n(p),v=e("./encode"),y=n(v),b=e("./ParseError"),g=n(b),m=e("./ParseGeoPoint"),C=n(m),j=e("./ParseObject"),k=n(j),O=e("./ParsePromise"),w=n(O),S=function(){function e(t){if((0,l["default"])(this,e),"string"==typeof t)"User"===t&&_["default"].get("PERFORM_USER_REWRITE")?this.className="_User":this.className=t;else if(t instanceof k["default"])this.className=t.className;else{if("function"!=typeof t)throw new TypeError("A ParseQuery must be constructed with a ParseObject or class name.");if("string"==typeof t.className)this.className=t.className;else{var r=new t;this.className=r.className}}this._where={},this._include=[],this._limit=-1,this._skip=0,this._extraOptions={}}return(0,f["default"])(e,[{key:"_orQuery",value:function(e){var t=e.map(function(e){return e.toJSON().where});return this._where.$or=t,this}},{key:"_addCondition",value:function(e,t,r){return this._where[e]&&"string"!=typeof this._where[e]||(this._where[e]={}),this._where[e][t]=(0,y["default"])(r,!1,!0),this}},{key:"_regexStartWith",value:function(e){return"^"+o(e)}},{key:"toJSON",value:function(){var e={where:this._where};this._include.length&&(e.include=this._include.join(",")),this._select&&(e.keys=this._select.join(",")),this._limit>=0&&(e.limit=this._limit),this._skip>0&&(e.skip=this._skip),this._order&&(e.order=this._order.join(","));for(var t in this._extraOptions)e[t]=this._extraOptions[t];return e}},{key:"get",value:function(e,t){this.equalTo("objectId",e);var r={};return t&&t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t&&t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),this.first(r).then(function(e){if(e)return e;var t=new g["default"](g["default"].OBJECT_NOT_FOUND,"Object not found.");return w["default"].error(t)})._thenRunCallbacks(t,null)}},{key:"find",value:function(e){var t=this;e=e||{};var r={};e.hasOwnProperty("useMasterKey")&&(r.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(r.sessionToken=e.sessionToken);var n=_["default"].getQueryController(),o=this._select;return n.find(this.className,this.toJSON(),r).then(function(e){return e.results.map(function(r){var n=e.className||t.className;return r.className||(r.className=n),o&&a(r,o),k["default"].fromJSON(r,!o)})})._thenRunCallbacks(e)}},{key:"count",value:function(e){e=e||{};var t={};e.hasOwnProperty("useMasterKey")&&(t.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(t.sessionToken=e.sessionToken);var r=_["default"].getQueryController(),n=this.toJSON();return n.limit=0,n.count=1,r.find(this.className,n,t).then(function(e){return e.count})._thenRunCallbacks(e)}},{key:"first",value:function(e){var t=this;e=e||{};var r={};e.hasOwnProperty("useMasterKey")&&(r.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(r.sessionToken=e.sessionToken);var n=_["default"].getQueryController(),o=this.toJSON();o.limit=1;var i=this._select;return n.find(this.className,o,r).then(function(e){var r=e.results;if(r[0])return r[0].className||(r[0].className=t.className),i&&a(r[0],i),k["default"].fromJSON(r[0],!i)})._thenRunCallbacks(e)}},{key:"each",value:function(t,r){if(r=r||{},this._order||this._skip||this._limit>=0)return w["default"].error("Cannot iterate on a query with sort, skip, or limit.")._thenRunCallbacks(r);new w["default"];var n=new e(this.className);n._limit=r.batchSize||100,n._include=this._include.map(function(e){return e}),this._select&&(n._select=this._select.map(function(e){return e})),n._where={};for(var o in this._where){var a=this._where[o];if(Array.isArray(a))n._where[o]=a.map(function(e){return e});else if(a&&"object"===("undefined"==typeof a?"undefined":(0,s["default"])(a))){var i={};n._where[o]=i;for(var u in a)i[u]=a[u]}else n._where[o]=a}n.ascending("objectId");var l={};r.hasOwnProperty("useMasterKey")&&(l.useMasterKey=r.useMasterKey),r.hasOwnProperty("sessionToken")&&(l.sessionToken=r.sessionToken);var c=!1;return w["default"]._continueWhile(function(){return!c},function(){return n.find(l).then(function(e){var r=w["default"].as();return e.forEach(function(e){r=r.then(function(){return t(e)})}),r.then(function(){e.length>=n._limit?n.greaterThan("objectId",e[e.length-1].id):c=!0})})})._thenRunCallbacks(r)}},{key:"equalTo",value:function(e,t){return"undefined"==typeof t?this.doesNotExist(e):(this._where[e]=(0,y["default"])(t,!1,!0),this)}},{key:"notEqualTo",value:function(e,t){return this._addCondition(e,"$ne",t)}},{key:"lessThan",value:function(e,t){return this._addCondition(e,"$lt",t)}},{key:"greaterThan",value:function(e,t){return this._addCondition(e,"$gt",t)}},{key:"lessThanOrEqualTo",value:function(e,t){return this._addCondition(e,"$lte",t)}},{key:"greaterThanOrEqualTo",value:function(e,t){return this._addCondition(e,"$gte",t)}},{key:"containedIn",value:function(e,t){return this._addCondition(e,"$in",t)}},{key:"notContainedIn",value:function(e,t){return this._addCondition(e,"$nin",t)}},{key:"containsAll",value:function(e,t){return this._addCondition(e,"$all",t)}},{key:"containsAllStartingWith",value:function(e,t){var r=this;return Array.isArray(t)||(t=[t]),t=t.map(function(e){return{$regex:r._regexStartWith(e)}}),this.containsAll(e,t)}},{key:"exists",value:function(e){return this._addCondition(e,"$exists",!0)}},{key:"doesNotExist",value:function(e){return this._addCondition(e,"$exists",!1)}},{key:"matches",value:function(e,t,r){return this._addCondition(e,"$regex",t),r||(r=""),t.ignoreCase&&(r+="i"),t.multiline&&(r+="m"),r.length&&this._addCondition(e,"$options",r),this}},{key:"matchesQuery",value:function(e,t){var r=t.toJSON();return r.className=t.className,this._addCondition(e,"$inQuery",r)}},{key:"doesNotMatchQuery",value:function(e,t){var r=t.toJSON();return r.className=t.className,this._addCondition(e,"$notInQuery",r)}},{key:"matchesKeyInQuery",value:function(e,t,r){var n=r.toJSON();return n.className=r.className,this._addCondition(e,"$select",{key:t,query:n})}},{key:"doesNotMatchKeyInQuery",value:function(e,t,r){var n=r.toJSON();return n.className=r.className,this._addCondition(e,"$dontSelect",{key:t,query:n})}},{key:"contains",value:function(e,t){if("string"!=typeof t)throw new Error("The value being searched for must be a string.");return this._addCondition(e,"$regex",o(t))}},{key:"startsWith",value:function(e,t){if("string"!=typeof t)throw new Error("The value being searched for must be a string.");return this._addCondition(e,"$regex",this._regexStartWith(t))}},{key:"endsWith",value:function(e,t){if("string"!=typeof t)throw new Error("The value being searched for must be a string.");return this._addCondition(e,"$regex",o(t)+"$")}},{key:"near",value:function(e,t){return t instanceof C["default"]||(t=new C["default"](t)),this._addCondition(e,"$nearSphere",t)}},{key:"withinRadians",value:function(e,t,r){return this.near(e,t),this._addCondition(e,"$maxDistance",r)}},{key:"withinMiles",value:function(e,t,r){return this.withinRadians(e,t,r/3958.8)}},{key:"withinKilometers",value:function(e,t,r){return this.withinRadians(e,t,r/6371)}},{key:"withinGeoBox",value:function(e,t,r){return t instanceof C["default"]||(t=new C["default"](t)),r instanceof C["default"]||(r=new C["default"](r)),this._addCondition(e,"$within",{$box:[t,r]}),this}},{key:"ascending",value:function(){this._order=[];for(var e=arguments.length,t=Array(e),r=0;r=200&&l.status<300){var e;try{e=JSON.parse(l.responseText)}catch(t){i.reject(t.toString())}e&&i.resolve(e,l.status,l)}else if(l.status>=500||0===l.status)if(++s-1)return!0;for(var r=0;r-1||e.dirty()||(0,u["default"])(e._getServerData()).length<1?e.toPointer():(n=n.concat(a),e._toFullJSON(n))}if(e instanceof y.Op||e instanceof c["default"]||e instanceof p["default"]||e instanceof g["default"])return e.toJSON();if(e instanceof d["default"]){if(!e.url())throw new Error("Tried to encode an unsaved file.");return e.toJSON()}if("[object Date]"===m.call(e)){if(isNaN(e))throw new Error("Tried to encode an invalid date.");return{__type:"Date",iso:e.toJSON()}}if("[object RegExp]"===m.call(e)&&"string"==typeof e.source)return e.source;if(Array.isArray(e))return e.map(function(e){return o(e,t,r,n)});if(e&&"object"===("undefined"==typeof e?"undefined":(0,i["default"])(e))){var s={};for(var l in e)s[l]=o(e[l],t,r,n);return s}return e}Object.defineProperty(r,"__esModule",{value:!0});var a=e("babel-runtime/helpers/typeof"),i=n(a),s=e("babel-runtime/core-js/object/keys"),u=n(s);r["default"]=function(e,t,r,n){return o(e,!!t,!!r,n||[])};var l=e("./ParseACL"),c=n(l),f=e("./ParseFile"),d=n(f),h=e("./ParseGeoPoint"),p=n(h),_=e("./ParseObject"),v=n(_),y=e("./ParseOp"),b=e("./ParseRelation"),g=n(b),m=Object.prototype.toString},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"./ParseOp":19,"./ParseRelation":22,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],37:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(("undefined"==typeof e?"undefined":(0,u["default"])(e))!==("undefined"==typeof t?"undefined":(0,u["default"])(t)))return!1;if(!e||"object"!==("undefined"==typeof e?"undefined":(0,u["default"])(e)))return e===t;if(Array.isArray(e)||Array.isArray(t)){if(!Array.isArray(e)||!Array.isArray(t))return!1;if(e.length!==t.length)return!1;for(var r=e.length;r--;)if(!o(e[r],t[r]))return!1;return!0}if(e instanceof c["default"]||e instanceof d["default"]||e instanceof p["default"]||e instanceof v["default"])return e.equals(t);if((0,i["default"])(e).length!==(0,i["default"])(t).length)return!1;for(var n in e)if(!o(e[n],t[n]))return!1;return!0}Object.defineProperty(r,"__esModule",{value:!0});var a=e("babel-runtime/core-js/object/keys"),i=n(a),s=e("babel-runtime/helpers/typeof"),u=n(s);r["default"]=o;var l=e("./ParseACL"),c=n(l),f=e("./ParseFile"),d=n(f),h=e("./ParseGeoPoint"),p=n(h),_=e("./ParseObject"),v=n(_)},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],38:[function(e,t,r){"use strict";function n(e){return e.replace(/[&<>\/'"]/g,function(e){return o[e]})}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=n;var o={"&":"&","<":"<",">":">","/":"/","'":"'",'"':"""}},{}],39:[function(e,t,r){"use strict";function n(e){return e.indexOf("r:")>-1}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=n},{}],40:[function(e,t,r){"use strict";function n(e){var t=new RegExp("^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})T([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})(.([0-9]+))?Z$"),r=t.exec(e);if(!r)return null;var n=r[1]||0,o=(r[2]||1)-1,a=r[3]||0,i=r[4]||0,s=r[5]||0,u=r[6]||0,l=r[8]||0;return new Date(Date.UTC(n,o,a,i,s,u,l))}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=n},{}],41:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e){var t=[];return e.forEach(function(e){e instanceof u["default"]?(0,i["default"])(t,e)||t.push(e):t.indexOf(e)<0&&t.push(e)}),t}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=o;var a=e("./arrayContainsObject"),i=n(a),s=e("./ParseObject"),u=n(s)},{"./ParseObject":18,"./arrayContainsObject":33}],42:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){var r={objects:{},files:[]},n=e.className+":"+e._getId();r.objects[n]=!e.dirty()||e;var o=e.attributes;for(var i in o)"object"===(0,s["default"])(o[i])&&a(o[i],r,!1,!!t);var u=[];for(var l in r.objects)l!==n&&r.objects[l]!==!0&&u.push(r.objects[l]);return u.concat(r.files)}function a(e,t,r,n){if(e instanceof f["default"]){if(!e.id&&r)throw new Error("Cannot create a pointer to an unsaved Object.");var o=e.className+":"+e._getId();if(!t.objects[o]){t.objects[o]=!e.dirty()||e;var i=e.attributes;for(var u in i)"object"===(0,s["default"])(i[u])&&a(i[u],t,!n,n)}}else{if(e instanceof l["default"])return void(!e.url()&&t.files.indexOf(e)<0&&t.files.push(e));if(!(e instanceof h["default"])){Array.isArray(e)&&e.forEach(function(e){"object"===("undefined"==typeof e?"undefined":(0,s["default"])(e))&&a(e,t,r,n)});for(var c in e)"object"===(0,s["default"])(e[c])&&a(e[c],t,r,n)}}}Object.defineProperty(r,"__esModule",{value:!0});var i=e("babel-runtime/helpers/typeof"),s=n(i);r["default"]=o;var u=e("./ParseFile"),l=n(u),c=e("./ParseObject"),f=n(c),d=e("./ParseRelation"),h=n(d)},{"./ParseFile":14,"./ParseObject":18,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],43:[function(e,t,r){t.exports={"default":e("core-js/library/fn/get-iterator"),__esModule:!0}},{"core-js/library/fn/get-iterator":62}],44:[function(e,t,r){t.exports={"default":e("core-js/library/fn/json/stringify"),__esModule:!0}},{"core-js/library/fn/json/stringify":63}],45:[function(e,t,r){t.exports={"default":e("core-js/library/fn/map"),__esModule:!0}},{"core-js/library/fn/map":64}],46:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/create"),__esModule:!0}},{"core-js/library/fn/object/create":65}],47:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/define-property"),__esModule:!0}},{"core-js/library/fn/object/define-property":66}],48:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/freeze"),__esModule:!0}},{"core-js/library/fn/object/freeze":67}],49:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/get-own-property-descriptor"),__esModule:!0}},{"core-js/library/fn/object/get-own-property-descriptor":68}],50:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/get-prototype-of"),__esModule:!0}},{"core-js/library/fn/object/get-prototype-of":69}],51:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/keys"),__esModule:!0}},{"core-js/library/fn/object/keys":70}],52:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/set-prototype-of"),__esModule:!0}},{"core-js/library/fn/object/set-prototype-of":71}],53:[function(e,t,r){t.exports={"default":e("core-js/library/fn/symbol"),__esModule:!0}},{"core-js/library/fn/symbol":72}],54:[function(e,t,r){t.exports={"default":e("core-js/library/fn/symbol/iterator"),__esModule:!0}},{"core-js/library/fn/symbol/iterator":73}],55:[function(e,t,r){t.exports={"default":e("core-js/library/fn/weak-map"),__esModule:!0}},{"core-js/library/fn/weak-map":74}],56:[function(e,t,r){"use strict";r.__esModule=!0,r["default"]=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},{}],57:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}r.__esModule=!0;var o=e("../core-js/object/define-property"),a=n(o);r["default"]=function(){function e(e,t){for(var r=0;rc;)if(s=u[c++],s!=s)return!0}else for(;l>c;c++)if((e||c in u)&&u[c]===r)return e||c||0;return!e&&-1}}},{"./_to-index":139,"./_to-iobject":141,"./_to-length":142}],81:[function(e,t,r){var n=e("./_ctx"),o=e("./_iobject"),a=e("./_to-object"),i=e("./_to-length"),s=e("./_array-species-create");t.exports=function(e,t){var r=1==e,u=2==e,l=3==e,c=4==e,f=6==e,d=5==e||f,h=t||s;return function(t,s,p){for(var _,v,y=a(t),b=o(y),g=n(s,p,3),m=i(b.length),C=0,j=r?h(t,m):u?h(t,0):void 0;m>C;C++)if((d||C in b)&&(_=b[C],v=g(_,C,y),e))if(r)j[C]=v;else if(v)switch(e){case 3:return!0;case 5:return _;case 6:return C;case 2:j.push(_)}else if(c)return!1;return f?-1:l||c?c:j}}},{"./_array-species-create":83,"./_ctx":91,"./_iobject":105,"./_to-length":142,"./_to-object":143}],82:[function(e,t,r){var n=e("./_is-object"),o=e("./_is-array"),a=e("./_wks")("species");t.exports=function(e){var t;return o(e)&&(t=e.constructor,"function"!=typeof t||t!==Array&&!o(t.prototype)||(t=void 0),n(t)&&(t=t[a],null===t&&(t=void 0))),void 0===t?Array:t}},{"./_is-array":107,"./_is-object":108,"./_wks":148}],83:[function(e,t,r){var n=e("./_array-species-constructor");t.exports=function(e,t){return new(n(e))(t)}},{"./_array-species-constructor":82}],84:[function(e,t,r){var n=e("./_cof"),o=e("./_wks")("toStringTag"),a="Arguments"==n(function(){return arguments}()),i=function(e,t){try{return e[t]}catch(r){}};t.exports=function(e){var t,r,s;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(r=i(t=Object(e),o))?r:a?n(t):"Object"==(s=n(t))&&"function"==typeof t.callee?"Arguments":s}},{"./_cof":85,"./_wks":148}],85:[function(e,t,r){var n={}.toString;t.exports=function(e){return n.call(e).slice(8,-1)}},{}],86:[function(e,t,r){"use strict";var n=e("./_object-dp").f,o=e("./_object-create"),a=e("./_redefine-all"),i=e("./_ctx"),s=e("./_an-instance"),u=e("./_defined"),l=e("./_for-of"),c=e("./_iter-define"),f=e("./_iter-step"),d=e("./_set-species"),h=e("./_descriptors"),p=e("./_meta").fastKey,_=h?"_s":"size",v=function(e,t){var r,n=p(t);if("F"!==n)return e._i[n];for(r=e._f;r;r=r.n)if(r.k==t)return r};t.exports={getConstructor:function(e,t,r,c){var f=e(function(e,n){s(e,f,t,"_i"),e._i=o(null),e._f=void 0,e._l=void 0,e[_]=0,void 0!=n&&l(n,r,e[c],e)});return a(f.prototype,{clear:function(){for(var e=this,t=e._i,r=e._f;r;r=r.n)r.r=!0,r.p&&(r.p=r.p.n=void 0),delete t[r.i];e._f=e._l=void 0,e[_]=0},"delete":function(e){var t=this,r=v(t,e);if(r){var n=r.n,o=r.p;delete t._i[r.i],r.r=!0,o&&(o.n=n),n&&(n.p=o),t._f==r&&(t._f=n),t._l==r&&(t._l=o),t[_]--}return!!r},forEach:function(e){s(this,f,"forEach");for(var t,r=i(e,arguments.length>1?arguments[1]:void 0,3);t=t?t.n:this._f;)for(r(t.v,t.k,this);t&&t.r;)t=t.p},has:function(e){return!!v(this,e)}}),h&&n(f.prototype,"size",{get:function(){return u(this[_])}}),f},def:function(e,t,r){var n,o,a=v(e,t);return a?a.v=r:(e._l=a={i:o=p(t,!0),k:t,v:r,p:n=e._l,n:void 0,r:!1},e._f||(e._f=a),n&&(n.n=a),e[_]++,"F"!==o&&(e._i[o]=a)),e},getEntry:v,setStrong:function(e,t,r){c(e,t,function(e,t){this._t=e,this._k=t,this._l=void 0},function(){for(var e=this,t=e._k,r=e._l;r&&r.r;)r=r.p;return e._t&&(e._l=r=r?r.n:e._t._f)?"keys"==t?f(0,r.k):"values"==t?f(0,r.v):f(0,[r.k,r.v]):(e._t=void 0,f(1))},r?"entries":"values",!r,!0),d(t)}}},{"./_an-instance":77,"./_ctx":91,"./_defined":92,"./_descriptors":93,"./_for-of":99,"./_iter-define":111,"./_iter-step":112,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_redefine-all":131,"./_set-species":134}],87:[function(e,t,r){var n=e("./_classof"),o=e("./_array-from-iterable");t.exports=function(e){return function(){if(n(this)!=e)throw TypeError(e+"#toJSON isn't generic");return o(this)}}},{"./_array-from-iterable":79,"./_classof":84}],88:[function(e,t,r){"use strict";var n=e("./_redefine-all"),o=e("./_meta").getWeak,a=e("./_an-object"),i=e("./_is-object"),s=e("./_an-instance"),u=e("./_for-of"),l=e("./_array-methods"),c=e("./_has"),f=l(5),d=l(6),h=0,p=function(e){return e._l||(e._l=new _)},_=function(){this.a=[]},v=function(e,t){return f(e.a,function(e){return e[0]===t})};_.prototype={get:function(e){var t=v(this,e);if(t)return t[1]},has:function(e){return!!v(this,e)},set:function(e,t){var r=v(this,e);r?r[1]=t:this.a.push([e,t])},"delete":function(e){var t=d(this.a,function(t){return t[0]===e});return~t&&this.a.splice(t,1),!!~t}},t.exports={getConstructor:function(e,t,r,a){var l=e(function(e,n){s(e,l,t,"_i"),e._i=h++,e._l=void 0,void 0!=n&&u(n,r,e[a],e)});return n(l.prototype,{"delete":function(e){if(!i(e))return!1;var t=o(e);return t===!0?p(this)["delete"](e):t&&c(t,this._i)&&delete t[this._i]},has:function(e){if(!i(e))return!1;var t=o(e);return t===!0?p(this).has(e):t&&c(t,this._i)}}),l},def:function(e,t,r){var n=o(a(t),!0);return n===!0?p(e).set(t,r):n[e._i]=r,e},ufstore:p}},{"./_an-instance":77,"./_an-object":78,"./_array-methods":81,"./_for-of":99,"./_has":101,"./_is-object":108,"./_meta":116,"./_redefine-all":131}],89:[function(e,t,r){"use strict";var n=e("./_global"),o=e("./_export"),a=e("./_meta"),i=e("./_fails"),s=e("./_hide"),u=e("./_redefine-all"),l=e("./_for-of"),c=e("./_an-instance"),f=e("./_is-object"),d=e("./_set-to-string-tag"),h=e("./_object-dp").f,p=e("./_array-methods")(0),_=e("./_descriptors");t.exports=function(e,t,r,v,y,b){var g=n[e],m=g,C=y?"set":"add",j=m&&m.prototype,k={};return _&&"function"==typeof m&&(b||j.forEach&&!i(function(){(new m).entries().next()}))?(m=t(function(t,r){c(t,m,e,"_c"),t._c=new g,void 0!=r&&l(r,y,t[C],t)}),p("add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON".split(","),function(e){var t="add"==e||"set"==e;e in j&&(!b||"clear"!=e)&&s(m.prototype,e,function(r,n){if(c(this,m,e),!t&&b&&!f(r))return"get"==e&&void 0;var o=this._c[e](0===r?0:r,n);return t?this:o})}),"size"in j&&h(m.prototype,"size",{get:function(){return this._c.size}})):(m=v.getConstructor(t,e,y,C),u(m.prototype,r),a.NEED=!0),d(m,e),k[e]=m,o(o.G+o.W+o.F,k),b||v.setStrong(m,e,y),m}},{"./_an-instance":77,"./_array-methods":81,"./_descriptors":93,"./_export":97,"./_fails":98,"./_for-of":99,"./_global":100,"./_hide":102,"./_is-object":108,"./_meta":116,"./_object-dp":119,"./_redefine-all":131,"./_set-to-string-tag":135}],90:[function(e,t,r){var n=t.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n)},{}],91:[function(e,t,r){var n=e("./_a-function");t.exports=function(e,t,r){if(n(e),void 0===t)return e;switch(r){case 1:return function(r){return e.call(t,r)};case 2:return function(r,n){return e.call(t,r,n)};case 3:return function(r,n,o){return e.call(t,r,n,o)}}return function(){return e.apply(t,arguments)}}},{"./_a-function":75}],92:[function(e,t,r){t.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},{}],93:[function(e,t,r){t.exports=!e("./_fails")(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},{"./_fails":98}],94:[function(e,t,r){var n=e("./_is-object"),o=e("./_global").document,a=n(o)&&n(o.createElement);t.exports=function(e){return a?o.createElement(e):{}}},{"./_global":100,"./_is-object":108}],95:[function(e,t,r){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},{}],96:[function(e,t,r){var n=e("./_object-keys"),o=e("./_object-gops"),a=e("./_object-pie");t.exports=function(e){var t=n(e),r=o.f;if(r)for(var i,s=r(e),u=a.f,l=0;s.length>l;)u.call(e,i=s[l++])&&t.push(i);return t}},{"./_object-gops":124,"./_object-keys":127,"./_object-pie":128}],97:[function(e,t,r){var n=e("./_global"),o=e("./_core"),a=e("./_ctx"),i=e("./_hide"),s="prototype",u=function(e,t,r){var l,c,f,d=e&u.F,h=e&u.G,p=e&u.S,_=e&u.P,v=e&u.B,y=e&u.W,b=h?o:o[t]||(o[t]={}),g=b[s],m=h?n:p?n[t]:(n[t]||{})[s];h&&(r=t);for(l in r)c=!d&&m&&void 0!==m[l],c&&l in b||(f=c?m[l]:r[l],b[l]=h&&"function"!=typeof m[l]?r[l]:v&&c?a(f,n):y&&m[l]==f?function(e){var t=function(t,r,n){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,r)}return new e(t,r,n)}return e.apply(this,arguments)};return t[s]=e[s],t}(f):_&&"function"==typeof f?a(Function.call,f):f,_&&((b.virtual||(b.virtual={}))[l]=f,e&u.R&&g&&!g[l]&&i(g,l,f)))};u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,t.exports=u},{"./_core":90,"./_ctx":91,"./_global":100,"./_hide":102}],98:[function(e,t,r){t.exports=function(e){try{return!!e()}catch(t){return!0}}},{}],99:[function(e,t,r){var n=e("./_ctx"),o=e("./_iter-call"),a=e("./_is-array-iter"),i=e("./_an-object"),s=e("./_to-length"),u=e("./core.get-iterator-method"),l={},c={},r=t.exports=function(e,t,r,f,d){var h,p,_,v,y=d?function(){return e}:u(e),b=n(r,f,t?2:1),g=0;if("function"!=typeof y)throw TypeError(e+" is not iterable!");if(a(y)){for(h=s(e.length);h>g;g++)if(v=t?b(i(p=e[g])[0],p[1]):b(e[g]),v===l||v===c)return v}else for(_=y.call(e);!(p=_.next()).done;)if(v=o(_,b,p.value,t),v===l||v===c)return v};r.BREAK=l,r.RETURN=c},{"./_an-object":78,"./_ctx":91,"./_is-array-iter":106,"./_iter-call":109,"./_to-length":142,"./core.get-iterator-method":149}],100:[function(e,t,r){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},{}],101:[function(e,t,r){var n={}.hasOwnProperty;t.exports=function(e,t){return n.call(e,t)}},{}],102:[function(e,t,r){var n=e("./_object-dp"),o=e("./_property-desc");t.exports=e("./_descriptors")?function(e,t,r){return n.f(e,t,o(1,r))}:function(e,t,r){return e[t]=r,e}},{"./_descriptors":93,"./_object-dp":119,"./_property-desc":130}],103:[function(e,t,r){t.exports=e("./_global").document&&document.documentElement},{"./_global":100}],104:[function(e,t,r){t.exports=!e("./_descriptors")&&!e("./_fails")(function(){return 7!=Object.defineProperty(e("./_dom-create")("div"),"a",{get:function(){return 7}}).a})},{"./_descriptors":93,"./_dom-create":94,"./_fails":98}],105:[function(e,t,r){var n=e("./_cof");t.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==n(e)?e.split(""):Object(e)}},{"./_cof":85}],106:[function(e,t,r){var n=e("./_iterators"),o=e("./_wks")("iterator"),a=Array.prototype;t.exports=function(e){return void 0!==e&&(n.Array===e||a[o]===e)}},{"./_iterators":113,"./_wks":148}],107:[function(e,t,r){var n=e("./_cof");t.exports=Array.isArray||function(e){return"Array"==n(e)}},{"./_cof":85}],108:[function(e,t,r){t.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},{}],109:[function(e,t,r){var n=e("./_an-object");t.exports=function(e,t,r,o){try{return o?t(n(r)[0],r[1]):t(r)}catch(a){var i=e["return"];throw void 0!==i&&n(i.call(e)),a}}},{"./_an-object":78}],110:[function(e,t,r){"use strict";var n=e("./_object-create"),o=e("./_property-desc"),a=e("./_set-to-string-tag"),i={};e("./_hide")(i,e("./_wks")("iterator"),function(){return this}),t.exports=function(e,t,r){e.prototype=n(i,{next:o(1,r)}),a(e,t+" Iterator")}},{"./_hide":102,"./_object-create":118,"./_property-desc":130,"./_set-to-string-tag":135,"./_wks":148}],111:[function(e,t,r){"use strict";var n=e("./_library"),o=e("./_export"),a=e("./_redefine"),i=e("./_hide"),s=e("./_has"),u=e("./_iterators"),l=e("./_iter-create"),c=e("./_set-to-string-tag"),f=e("./_object-gpo"),d=e("./_wks")("iterator"),h=!([].keys&&"next"in[].keys()),p="@@iterator",_="keys",v="values",y=function(){return this};t.exports=function(e,t,r,b,g,m,C){l(r,t,b);var j,k,O,w=function(e){if(!h&&e in A)return A[e];switch(e){case _:return function(){return new r(this,e)};case v:return function(){return new r(this,e)}}return function(){return new r(this,e)}},S=t+" Iterator",E=g==v,P=!1,A=e.prototype,I=A[d]||A[p]||g&&A[g],T=I||w(g),N=g?E?w("entries"):T:void 0,R="Array"==t?A.entries||I:I;if(R&&(O=f(R.call(new e)),O!==Object.prototype&&(c(O,S,!0),n||s(O,d)||i(O,d,y))),E&&I&&I.name!==v&&(P=!0,T=function(){return I.call(this)}),n&&!C||!h&&!P&&A[d]||i(A,d,T),u[t]=T,u[S]=y,g)if(j={values:E?T:w(v),keys:m?T:w(_),entries:N},C)for(k in j)k in A||a(A,k,j[k]);else o(o.P+o.F*(h||P),t,j);return j}},{"./_export":97,"./_has":101,"./_hide":102,"./_iter-create":110,"./_iterators":113,"./_library":115,"./_object-gpo":125,"./_redefine":132,"./_set-to-string-tag":135,"./_wks":148}],112:[function(e,t,r){t.exports=function(e,t){return{value:t,done:!!e}}},{}],113:[function(e,t,r){t.exports={}},{}],114:[function(e,t,r){var n=e("./_object-keys"),o=e("./_to-iobject");t.exports=function(e,t){for(var r,a=o(e),i=n(a),s=i.length,u=0;s>u;)if(a[r=i[u++]]===t)return r}},{"./_object-keys":127,"./_to-iobject":141}],115:[function(e,t,r){t.exports=!0},{}],116:[function(e,t,r){var n=e("./_uid")("meta"),o=e("./_is-object"),a=e("./_has"),i=e("./_object-dp").f,s=0,u=Object.isExtensible||function(){return!0},l=!e("./_fails")(function(){return u(Object.preventExtensions({}))}),c=function(e){i(e,n,{value:{i:"O"+ ++s,w:{}}})},f=function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!a(e,n)){if(!u(e))return"F";if(!t)return"E";c(e)}return e[n].i},d=function(e,t){if(!a(e,n)){if(!u(e))return!0;if(!t)return!1;c(e)}return e[n].w},h=function(e){return l&&p.NEED&&u(e)&&!a(e,n)&&c(e),e},p=t.exports={KEY:n,NEED:!1,fastKey:f,getWeak:d,onFreeze:h}},{"./_fails":98,"./_has":101,"./_is-object":108,"./_object-dp":119,"./_uid":145}],117:[function(e,t,r){"use strict";var n=e("./_object-keys"),o=e("./_object-gops"),a=e("./_object-pie"),i=e("./_to-object"),s=e("./_iobject"),u=Object.assign;t.exports=!u||e("./_fails")(function(){var e={},t={},r=Symbol(),n="abcdefghijklmnopqrst";return e[r]=7,n.split("").forEach(function(e){t[e]=e}),7!=u({},e)[r]||Object.keys(u({},t)).join("")!=n})?function(e,t){for(var r=i(e),u=arguments.length,l=1,c=o.f,f=a.f;u>l;)for(var d,h=s(arguments[l++]),p=c?n(h).concat(c(h)):n(h),_=p.length,v=0;_>v;)f.call(h,d=p[v++])&&(r[d]=h[d]);return r}:u},{"./_fails":98,"./_iobject":105,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_to-object":143}],118:[function(e,t,r){var n=e("./_an-object"),o=e("./_object-dps"),a=e("./_enum-bug-keys"),i=e("./_shared-key")("IE_PROTO"),s=function(){},u="prototype",l=function(){var t,r=e("./_dom-create")("iframe"),n=a.length,o="<",i=">";for(r.style.display="none",e("./_html").appendChild(r),r.src="javascript:",t=r.contentWindow.document,t.open(),t.write(o+"script"+i+"document.F=Object"+o+"/script"+i),t.close(),l=t.F;n--;)delete l[u][a[n]];return l()};t.exports=Object.create||function(e,t){var r;return null!==e?(s[u]=n(e),r=new s,s[u]=null,r[i]=e):r=l(),void 0===t?r:o(r,t)}},{"./_an-object":78,"./_dom-create":94,"./_enum-bug-keys":95,"./_html":103,"./_object-dps":120,"./_shared-key":136}],119:[function(e,t,r){var n=e("./_an-object"),o=e("./_ie8-dom-define"),a=e("./_to-primitive"),i=Object.defineProperty;r.f=e("./_descriptors")?Object.defineProperty:function(e,t,r){if(n(e),t=a(t,!0),n(r),o)try{return i(e,t,r)}catch(s){}if("get"in r||"set"in r)throw TypeError("Accessors not supported!");return"value"in r&&(e[t]=r.value),e}},{"./_an-object":78,"./_descriptors":93,"./_ie8-dom-define":104,"./_to-primitive":144}],120:[function(e,t,r){var n=e("./_object-dp"),o=e("./_an-object"),a=e("./_object-keys");t.exports=e("./_descriptors")?Object.defineProperties:function(e,t){o(e);for(var r,i=a(t),s=i.length,u=0;s>u;)n.f(e,r=i[u++],t[r]);return e}},{"./_an-object":78,"./_descriptors":93,"./_object-dp":119,"./_object-keys":127}],121:[function(e,t,r){var n=e("./_object-pie"),o=e("./_property-desc"),a=e("./_to-iobject"),i=e("./_to-primitive"),s=e("./_has"),u=e("./_ie8-dom-define"),l=Object.getOwnPropertyDescriptor;r.f=e("./_descriptors")?l:function(e,t){if(e=a(e),t=i(t,!0),u)try{return l(e,t)}catch(r){}if(s(e,t))return o(!n.f.call(e,t),e[t])}},{"./_descriptors":93,"./_has":101,"./_ie8-dom-define":104,"./_object-pie":128,"./_property-desc":130,"./_to-iobject":141,"./_to-primitive":144}],122:[function(e,t,r){var n=e("./_to-iobject"),o=e("./_object-gopn").f,a={}.toString,i="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(e){try{return o(e)}catch(t){return i.slice()}};t.exports.f=function(e){return i&&"[object Window]"==a.call(e)?s(e):o(n(e))}},{"./_object-gopn":123,"./_to-iobject":141}],123:[function(e,t,r){var n=e("./_object-keys-internal"),o=e("./_enum-bug-keys").concat("length","prototype");r.f=Object.getOwnPropertyNames||function(e){return n(e,o)}},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],124:[function(e,t,r){r.f=Object.getOwnPropertySymbols},{}],125:[function(e,t,r){var n=e("./_has"),o=e("./_to-object"),a=e("./_shared-key")("IE_PROTO"),i=Object.prototype;t.exports=Object.getPrototypeOf||function(e){return e=o(e),n(e,a)?e[a]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?i:null}},{"./_has":101,"./_shared-key":136,"./_to-object":143}],126:[function(e,t,r){var n=e("./_has"),o=e("./_to-iobject"),a=e("./_array-includes")(!1),i=e("./_shared-key")("IE_PROTO");t.exports=function(e,t){var r,s=o(e),u=0,l=[];for(r in s)r!=i&&n(s,r)&&l.push(r);for(;t.length>u;)n(s,r=t[u++])&&(~a(l,r)||l.push(r));return l}},{"./_array-includes":80,"./_has":101,"./_shared-key":136,"./_to-iobject":141}],127:[function(e,t,r){var n=e("./_object-keys-internal"),o=e("./_enum-bug-keys");t.exports=Object.keys||function(e){return n(e,o)}},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],128:[function(e,t,r){r.f={}.propertyIsEnumerable},{}],129:[function(e,t,r){var n=e("./_export"),o=e("./_core"),a=e("./_fails");t.exports=function(e,t){var r=(o.Object||{})[e]||Object[e],i={};i[e]=t(r),n(n.S+n.F*a(function(){r(1)}),"Object",i)}},{"./_core":90,"./_export":97,"./_fails":98}],130:[function(e,t,r){t.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},{}],131:[function(e,t,r){var n=e("./_hide");t.exports=function(e,t,r){for(var o in t)r&&e[o]?e[o]=t[o]:n(e,o,t[o]);return e}},{"./_hide":102}],132:[function(e,t,r){t.exports=e("./_hide")},{"./_hide":102}],133:[function(e,t,r){var n=e("./_is-object"),o=e("./_an-object"),a=function(e,t){if(o(e),!n(t)&&null!==t)throw TypeError(t+": can't set as prototype!")};t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,r,n){try{n=e("./_ctx")(Function.call,e("./_object-gopd").f(Object.prototype,"__proto__").set,2),n(t,[]),r=!(t instanceof Array)}catch(o){r=!0}return function(e,t){return a(e,t),r?e.__proto__=t:n(e,t),e}}({},!1):void 0),check:a}},{"./_an-object":78,"./_ctx":91,"./_is-object":108,"./_object-gopd":121}],134:[function(e,t,r){"use strict";var n=e("./_global"),o=e("./_core"),a=e("./_object-dp"),i=e("./_descriptors"),s=e("./_wks")("species");t.exports=function(e){var t="function"==typeof o[e]?o[e]:n[e];i&&t&&!t[s]&&a.f(t,s,{configurable:!0,get:function(){return this}})}},{"./_core":90,"./_descriptors":93,"./_global":100,"./_object-dp":119,"./_wks":148}],135:[function(e,t,r){var n=e("./_object-dp").f,o=e("./_has"),a=e("./_wks")("toStringTag");t.exports=function(e,t,r){e&&!o(e=r?e:e.prototype,a)&&n(e,a,{configurable:!0,value:t})}},{"./_has":101,"./_object-dp":119,"./_wks":148}],136:[function(e,t,r){var n=e("./_shared")("keys"),o=e("./_uid");t.exports=function(e){return n[e]||(n[e]=o(e))}},{"./_shared":137,"./_uid":145}],137:[function(e,t,r){var n=e("./_global"),o="__core-js_shared__",a=n[o]||(n[o]={});t.exports=function(e){return a[e]||(a[e]={})}},{"./_global":100}],138:[function(e,t,r){var n=e("./_to-integer"),o=e("./_defined");t.exports=function(e){return function(t,r){var a,i,s=String(o(t)),u=n(r),l=s.length;return u<0||u>=l?e?"":void 0:(a=s.charCodeAt(u),a<55296||a>56319||u+1===l||(i=s.charCodeAt(u+1))<56320||i>57343?e?s.charAt(u):a:e?s.slice(u,u+2):(a-55296<<10)+(i-56320)+65536)}}},{"./_defined":92,"./_to-integer":140}],139:[function(e,t,r){var n=e("./_to-integer"),o=Math.max,a=Math.min;t.exports=function(e,t){return e=n(e),e<0?o(e+t,0):a(e,t)}},{"./_to-integer":140}],140:[function(e,t,r){var n=Math.ceil,o=Math.floor;t.exports=function(e){return isNaN(e=+e)?0:(e>0?o:n)(e)}},{}],141:[function(e,t,r){var n=e("./_iobject"),o=e("./_defined");t.exports=function(e){return n(o(e))}},{"./_defined":92,"./_iobject":105}],142:[function(e,t,r){var n=e("./_to-integer"),o=Math.min;t.exports=function(e){return e>0?o(n(e),9007199254740991):0}},{"./_to-integer":140}],143:[function(e,t,r){var n=e("./_defined");t.exports=function(e){return Object(n(e))}},{"./_defined":92}],144:[function(e,t,r){var n=e("./_is-object");t.exports=function(e,t){if(!n(e))return e;var r,o;if(t&&"function"==typeof(r=e.toString)&&!n(o=r.call(e)))return o;if("function"==typeof(r=e.valueOf)&&!n(o=r.call(e)))return o;if(!t&&"function"==typeof(r=e.toString)&&!n(o=r.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},{"./_is-object":108}],145:[function(e,t,r){var n=0,o=Math.random();t.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+o).toString(36))}},{}],146:[function(e,t,r){var n=e("./_global"),o=e("./_core"),a=e("./_library"),i=e("./_wks-ext"),s=e("./_object-dp").f;t.exports=function(e){var t=o.Symbol||(o.Symbol=a?{}:n.Symbol||{});"_"==e.charAt(0)||e in t||s(t,e,{value:i.f(e)})}},{"./_core":90,"./_global":100,"./_library":115,"./_object-dp":119,"./_wks-ext":147}],147:[function(e,t,r){r.f=e("./_wks")},{"./_wks":148}],148:[function(e,t,r){var n=e("./_shared")("wks"),o=e("./_uid"),a=e("./_global").Symbol,i="function"==typeof a,s=t.exports=function(e){return n[e]||(n[e]=i&&a[e]||(i?a:o)("Symbol."+e))};s.store=n},{"./_global":100,"./_shared":137,"./_uid":145}],149:[function(e,t,r){var n=e("./_classof"),o=e("./_wks")("iterator"),a=e("./_iterators");t.exports=e("./_core").getIteratorMethod=function(e){if(void 0!=e)return e[o]||e["@@iterator"]||a[n(e)]}},{"./_classof":84,"./_core":90,"./_iterators":113,"./_wks":148}],150:[function(e,t,r){var n=e("./_an-object"),o=e("./core.get-iterator-method");t.exports=e("./_core").getIterator=function(e){var t=o(e);if("function"!=typeof t)throw TypeError(e+" is not iterable!");return n(t.call(e))}},{"./_an-object":78,"./_core":90,"./core.get-iterator-method":149}],151:[function(e,t,r){"use strict";var n=e("./_add-to-unscopables"),o=e("./_iter-step"),a=e("./_iterators"),i=e("./_to-iobject");t.exports=e("./_iter-define")(Array,"Array",function(e,t){this._t=i(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,r=this._i++;return!e||r>=e.length?(this._t=void 0,o(1)):"keys"==t?o(0,r):"values"==t?o(0,e[r]):o(0,[r,e[r]])},"values"),a.Arguments=a.Array,n("keys"),n("values"),n("entries")},{"./_add-to-unscopables":76,"./_iter-define":111,"./_iter-step":112,"./_iterators":113,"./_to-iobject":141}],152:[function(e,t,r){"use strict";var n=e("./_collection-strong");t.exports=e("./_collection")("Map",function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}},{get:function(e){var t=n.getEntry(this,e);return t&&t.v},set:function(e,t){return n.def(this,0===e?0:e,t)}},n,!0)},{"./_collection":89,"./_collection-strong":86}],153:[function(e,t,r){var n=e("./_export");n(n.S,"Object",{create:e("./_object-create")})},{"./_export":97,"./_object-create":118}],154:[function(e,t,r){var n=e("./_export");n(n.S+n.F*!e("./_descriptors"),"Object",{defineProperty:e("./_object-dp").f})},{"./_descriptors":93,"./_export":97,"./_object-dp":119}],155:[function(e,t,r){var n=e("./_is-object"),o=e("./_meta").onFreeze;e("./_object-sap")("freeze",function(e){return function(t){return e&&n(t)?e(o(t)):t}})},{"./_is-object":108,"./_meta":116,"./_object-sap":129}],156:[function(e,t,r){var n=e("./_to-iobject"),o=e("./_object-gopd").f;e("./_object-sap")("getOwnPropertyDescriptor",function(){return function(e,t){return o(n(e),t)}})},{"./_object-gopd":121,"./_object-sap":129,"./_to-iobject":141}],157:[function(e,t,r){var n=e("./_to-object"),o=e("./_object-gpo");e("./_object-sap")("getPrototypeOf",function(){return function(e){return o(n(e))}})},{"./_object-gpo":125,"./_object-sap":129,"./_to-object":143}],158:[function(e,t,r){var n=e("./_to-object"),o=e("./_object-keys");e("./_object-sap")("keys",function(){return function(e){return o(n(e))}})},{"./_object-keys":127,"./_object-sap":129,"./_to-object":143}],159:[function(e,t,r){var n=e("./_export");n(n.S,"Object",{setPrototypeOf:e("./_set-proto").set})},{"./_export":97,"./_set-proto":133}],160:[function(e,t,r){},{}],161:[function(e,t,r){"use strict";var n=e("./_string-at")(!0);e("./_iter-define")(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,r=this._i;return r>=t.length?{value:void 0,done:!0}:(e=n(t,r),this._i+=e.length,{value:e,done:!1})})},{"./_iter-define":111,"./_string-at":138}],162:[function(e,t,r){"use strict";var n=e("./_global"),o=e("./_has"),a=e("./_descriptors"),i=e("./_export"),s=e("./_redefine"),u=e("./_meta").KEY,l=e("./_fails"),c=e("./_shared"),f=e("./_set-to-string-tag"),d=e("./_uid"),h=e("./_wks"),p=e("./_wks-ext"),_=e("./_wks-define"),v=e("./_keyof"),y=e("./_enum-keys"),b=e("./_is-array"),g=e("./_an-object"),m=e("./_to-iobject"),C=e("./_to-primitive"),j=e("./_property-desc"),k=e("./_object-create"),O=e("./_object-gopn-ext"),w=e("./_object-gopd"),S=e("./_object-dp"),E=e("./_object-keys"),P=w.f,A=S.f,I=O.f,T=n.Symbol,N=n.JSON,R=N&&N.stringify,M="prototype",x=h("_hidden"),D=h("toPrimitive"),L={}.propertyIsEnumerable,U=c("symbol-registry"),F=c("symbols"),K=c("op-symbols"),q=Object[M],J="function"==typeof T,W=n.QObject,Q=!W||!W[M]||!W[M].findChild,B=a&&l(function(){return 7!=k(A({},"a",{get:function(){return A(this,"a",{value:7}).a}})).a})?function(e,t,r){var n=P(q,t);n&&delete q[t],A(e,t,r),n&&e!==q&&A(q,t,n)}:A,V=function(e){var t=F[e]=k(T[M]);return t._k=e,t},G=J&&"symbol"==typeof T.iterator?function(e){return"symbol"==typeof e}:function(e){return e instanceof T},z=function(e,t,r){return e===q&&z(K,t,r),g(e),t=C(t,!0),g(r),o(F,t)?(r.enumerable?(o(e,x)&&e[x][t]&&(e[x][t]=!1),r=k(r,{enumerable:j(0,!1)})):(o(e,x)||A(e,x,j(1,{})),e[x][t]=!0),B(e,t,r)):A(e,t,r)},Y=function(e,t){g(e);for(var r,n=y(t=m(t)),o=0,a=n.length;a>o;)z(e,r=n[o++],t[r]);return e},H=function(e,t){return void 0===t?k(e):Y(k(e),t); +},$=function(e){var t=L.call(this,e=C(e,!0));return!(this===q&&o(F,e)&&!o(K,e))&&(!(t||!o(this,e)||!o(F,e)||o(this,x)&&this[x][e])||t)},X=function(e,t){if(e=m(e),t=C(t,!0),e!==q||!o(F,t)||o(K,t)){var r=P(e,t);return!r||!o(F,t)||o(e,x)&&e[x][t]||(r.enumerable=!0),r}},Z=function(e){for(var t,r=I(m(e)),n=[],a=0;r.length>a;)o(F,t=r[a++])||t==x||t==u||n.push(t);return n},ee=function(e){for(var t,r=e===q,n=I(r?K:m(e)),a=[],i=0;n.length>i;)!o(F,t=n[i++])||r&&!o(q,t)||a.push(F[t]);return a};J||(T=function(){if(this instanceof T)throw TypeError("Symbol is not a constructor!");var e=d(arguments.length>0?arguments[0]:void 0),t=function(r){this===q&&t.call(K,r),o(this,x)&&o(this[x],e)&&(this[x][e]=!1),B(this,e,j(1,r))};return a&&Q&&B(q,e,{configurable:!0,set:t}),V(e)},s(T[M],"toString",function(){return this._k}),w.f=X,S.f=z,e("./_object-gopn").f=O.f=Z,e("./_object-pie").f=$,e("./_object-gops").f=ee,a&&!e("./_library")&&s(q,"propertyIsEnumerable",$,!0),p.f=function(e){return V(h(e))}),i(i.G+i.W+i.F*!J,{Symbol:T});for(var te="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),re=0;te.length>re;)h(te[re++]);for(var te=E(h.store),re=0;te.length>re;)_(te[re++]);i(i.S+i.F*!J,"Symbol",{"for":function(e){return o(U,e+="")?U[e]:U[e]=T(e)},keyFor:function(e){if(G(e))return v(U,e);throw TypeError(e+" is not a symbol!")},useSetter:function(){Q=!0},useSimple:function(){Q=!1}}),i(i.S+i.F*!J,"Object",{create:H,defineProperty:z,defineProperties:Y,getOwnPropertyDescriptor:X,getOwnPropertyNames:Z,getOwnPropertySymbols:ee}),N&&i(i.S+i.F*(!J||l(function(){var e=T();return"[null]"!=R([e])||"{}"!=R({a:e})||"{}"!=R(Object(e))})),"JSON",{stringify:function(e){if(void 0!==e&&!G(e)){for(var t,r,n=[e],o=1;arguments.length>o;)n.push(arguments[o++]);return t=n[1],"function"==typeof t&&(r=t),!r&&b(t)||(t=function(e,t){if(r&&(t=r.call(this,e,t)),!G(t))return t}),n[1]=t,R.apply(N,n)}}}),T[M][D]||e("./_hide")(T[M],D,T[M].valueOf),f(T,"Symbol"),f(Math,"Math",!0),f(n.JSON,"JSON",!0)},{"./_an-object":78,"./_descriptors":93,"./_enum-keys":96,"./_export":97,"./_fails":98,"./_global":100,"./_has":101,"./_hide":102,"./_is-array":107,"./_keyof":114,"./_library":115,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_object-gopd":121,"./_object-gopn":123,"./_object-gopn-ext":122,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_property-desc":130,"./_redefine":132,"./_set-to-string-tag":135,"./_shared":137,"./_to-iobject":141,"./_to-primitive":144,"./_uid":145,"./_wks":148,"./_wks-define":146,"./_wks-ext":147}],163:[function(e,t,r){"use strict";var n,o=e("./_array-methods")(0),a=e("./_redefine"),i=e("./_meta"),s=e("./_object-assign"),u=e("./_collection-weak"),l=e("./_is-object"),c=i.getWeak,f=Object.isExtensible,d=u.ufstore,h={},p=function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}},_={get:function(e){if(l(e)){var t=c(e);return t===!0?d(this).get(e):t?t[this._i]:void 0}},set:function(e,t){return u.def(this,e,t)}},v=t.exports=e("./_collection")("WeakMap",p,_,u,!0,!0);7!=(new v).set((Object.freeze||Object)(h),7).get(h)&&(n=u.getConstructor(p),s(n.prototype,_),i.NEED=!0,o(["delete","has","get","set"],function(e){var t=v.prototype,r=t[e];a(t,e,function(t,o){if(l(t)&&!f(t)){this._f||(this._f=new n);var a=this._f[e](t,o);return"set"==e?this:a}return r.call(this,t,o)})}))},{"./_array-methods":81,"./_collection":89,"./_collection-weak":88,"./_is-object":108,"./_meta":116,"./_object-assign":117,"./_redefine":132}],164:[function(e,t,r){var n=e("./_export");n(n.P+n.R,"Map",{toJSON:e("./_collection-to-json")("Map")})},{"./_collection-to-json":87,"./_export":97}],165:[function(e,t,r){e("./_wks-define")("asyncIterator")},{"./_wks-define":146}],166:[function(e,t,r){e("./_wks-define")("observable")},{"./_wks-define":146}],167:[function(e,t,r){e("./es6.array.iterator");for(var n=e("./_global"),o=e("./_hide"),a=e("./_iterators"),i=e("./_wks")("toStringTag"),s=["NodeList","DOMTokenList","MediaList","StyleSheetList","CSSRuleList"],u=0;u<5;u++){var l=s[u],c=n[l],f=c&&c.prototype;f&&!f[i]&&o(f,i,l),a[l]=a.Array}},{"./_global":100,"./_hide":102,"./_iterators":113,"./_wks":148,"./es6.array.iterator":151}],168:[function(e,t,r){arguments[4][160][0].apply(r,arguments)},{dup:160}],169:[function(e,t,r){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function o(e){return"function"==typeof e}function a(e){return"number"==typeof e}function i(e){return"object"==typeof e&&null!==e}function s(e){return void 0===e}t.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!a(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,r,n,a,u,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||i(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;throw TypeError('Uncaught, unspecified "error" event.')}if(r=this._events[e],s(r))return!1;if(o(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:for(n=arguments.length,a=new Array(n-1),u=1;u0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())}return this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!o(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},n.prototype.removeListener=function(e,t){var r,n,a,s;if(!o(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],a=r.length,n=-1,r===t||o(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(i(r)){for(s=a;s-- >0;)if(r[s]===t||r[s].listener&&r[s].listener===t){n=s;break}if(n<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],o(r))this.removeListener(e,r);else for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?o(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.listenerCount=function(e,t){var r;return r=e._events&&e._events[t]?o(e._events[t])?1:e._events[t].length:0}},{}]},{},[10])(10)}); \ No newline at end of file diff --git a/lib/browser/Analytics.js b/lib/browser/Analytics.js new file mode 100644 index 000000000..e5bddf088 --- /dev/null +++ b/lib/browser/Analytics.js @@ -0,0 +1,89 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.track = track; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Parse.Analytics provides an interface to Parse's logging and analytics + * backend. + * + * @class Parse.Analytics + * @static + */ + +/** + * Tracks the occurrence of a custom event with additional dimensions. + * Parse will store a data point at the time of invocation with the given + * event name. + * + * Dimensions will allow segmentation of the occurrences of this custom + * event. Keys and values should be {@code String}s, and will throw + * otherwise. + * + * To track a user signup along with additional metadata, consider the + * following: + *
      + * var dimensions = {
      + *  gender: 'm',
      + *  source: 'web',
      + *  dayType: 'weekend'
      + * };
      + * Parse.Analytics.track('signup', dimensions);
      + * 
      + * + * There is a default limit of 8 dimensions per event tracked. + * + * @method track + * @param {String} name The name of the custom event to report to Parse as + * having happened. + * @param {Object} dimensions The dictionary of information by which to + * segment this event. + * @param {Object} options A Backbone-style callback object. + * @return {Parse.Promise} A promise that is resolved when the round-trip + * to the server completes. + */ +function track(name, dimensions, options) { + name = name || ''; + name = name.replace(/^\s*/, ''); + name = name.replace(/\s*$/, ''); + if (name.length === 0) { + throw new TypeError('A name for the custom event must be provided'); + } + + for (var key in dimensions) { + if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { + throw new TypeError('track() dimensions expects keys and values of type "string".'); + } + } + + options = options || {}; + return _CoreManager2.default.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var DefaultController = { + track: function (name, dimensions) { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); + } +}; + +_CoreManager2.default.setAnalyticsController(DefaultController); \ No newline at end of file diff --git a/lib/browser/Cloud.js b/lib/browser/Cloud.js new file mode 100644 index 000000000..72c333750 --- /dev/null +++ b/lib/browser/Cloud.js @@ -0,0 +1,109 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = run; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains functions for calling and declaring + * cloud functions. + *

      + * Some functions are only available from Cloud Code. + *

      + * + * @class Parse.Cloud + * @static + */ + +/** + * Makes a call to a cloud function. + * @method run + * @param {String} name The function name. + * @param {Object} data The parameters to send to the cloud function. + * @param {Object} options A Backbone-style options object + * options.success, if set, should be a function to handle a successful + * call to a cloud function. options.error should be a function that + * handles an error running the cloud function. Both functions are + * optional. Both functions take a single argument. + * @return {Parse.Promise} A promise that will be resolved with the result + * of the function. + */ +function run(name, data, options) { + options = options || {}; + + if (typeof name !== 'string' || name.length === 0) { + throw new TypeError('Cloud function name must be a string.'); + } + + var requestOptions = {}; + if (options.useMasterKey) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.sessionToken) { + requestOptions.sessionToken = options.sessionToken; + } + + return _CoreManager2.default.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var DefaultController = { + run: function (name, data, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + var payload = (0, _encode2.default)(data, true); + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + requestOptions.sessionToken = options.sessionToken; + } + + var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); + + return request.then(function (res) { + var decoded = (0, _decode2.default)(res); + if (decoded && decoded.hasOwnProperty('result')) { + return _ParsePromise2.default.as(decoded.result); + } + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); + })._thenRunCallbacks(options); + } +}; + +_CoreManager2.default.setCloudController(DefaultController); \ No newline at end of file diff --git a/lib/browser/CoreManager.js b/lib/browser/CoreManager.js new file mode 100644 index 000000000..20d66a5f1 --- /dev/null +++ b/lib/browser/CoreManager.js @@ -0,0 +1,161 @@ +'use strict'; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var config = { + // Defaults + IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, + REQUEST_ATTEMPT_LIMIT: 5, + SERVER_URL: 'https://api.parse.com/1', + LIVEQUERY_SERVER_URL: null, + VERSION: 'js' + '1.9.2', + APPLICATION_ID: null, + JAVASCRIPT_KEY: null, + MASTER_KEY: null, + USE_MASTER_KEY: false, + PERFORM_USER_REWRITE: true, + FORCE_REVOCABLE_SESSION: false +}; + +function requireMethods(name, methods, controller) { + methods.forEach(function (func) { + if (typeof controller[func] !== 'function') { + throw new Error(name + ' must implement ' + func + '()'); + } + }); +} + +module.exports = { + get: function (key) { + if (config.hasOwnProperty(key)) { + return config[key]; + } + throw new Error('Configuration key not found: ' + key); + }, + + set: function (key, value) { + config[key] = value; + }, + + /* Specialized Controller Setters/Getters */ + + setAnalyticsController: function (controller) { + requireMethods('AnalyticsController', ['track'], controller); + config['AnalyticsController'] = controller; + }, + getAnalyticsController: function () { + return config['AnalyticsController']; + }, + setCloudController: function (controller) { + requireMethods('CloudController', ['run'], controller); + config['CloudController'] = controller; + }, + getCloudController: function () { + return config['CloudController']; + }, + setConfigController: function (controller) { + requireMethods('ConfigController', ['current', 'get'], controller); + config['ConfigController'] = controller; + }, + getConfigController: function () { + return config['ConfigController']; + }, + setFileController: function (controller) { + requireMethods('FileController', ['saveFile', 'saveBase64'], controller); + config['FileController'] = controller; + }, + getFileController: function () { + return config['FileController']; + }, + setInstallationController: function (controller) { + requireMethods('InstallationController', ['currentInstallationId'], controller); + config['InstallationController'] = controller; + }, + getInstallationController: function () { + return config['InstallationController']; + }, + setObjectController: function (controller) { + requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); + config['ObjectController'] = controller; + }, + getObjectController: function () { + return config['ObjectController']; + }, + setObjectStateController: function (controller) { + requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); + + config['ObjectStateController'] = controller; + }, + getObjectStateController: function () { + return config['ObjectStateController']; + }, + setPushController: function (controller) { + requireMethods('PushController', ['send'], controller); + config['PushController'] = controller; + }, + getPushController: function () { + return config['PushController']; + }, + setQueryController: function (controller) { + requireMethods('QueryController', ['find'], controller); + config['QueryController'] = controller; + }, + getQueryController: function () { + return config['QueryController']; + }, + setRESTController: function (controller) { + requireMethods('RESTController', ['request', 'ajax'], controller); + config['RESTController'] = controller; + }, + getRESTController: function () { + return config['RESTController']; + }, + setSessionController: function (controller) { + requireMethods('SessionController', ['getSession'], controller); + config['SessionController'] = controller; + }, + getSessionController: function () { + return config['SessionController']; + }, + setStorageController: function (controller) { + if (controller.async) { + requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); + } else { + requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); + } + config['StorageController'] = controller; + }, + getStorageController: function () { + return config['StorageController']; + }, + setUserController: function (controller) { + requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); + config['UserController'] = controller; + }, + getUserController: function () { + return config['UserController']; + }, + setLiveQueryController: function (controller) { + requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); + config['LiveQueryController'] = controller; + }, + getLiveQueryController: function () { + return config['LiveQueryController']; + }, + setHooksController: function (controller) { + requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); + config['HooksController'] = controller; + }, + getHooksController: function () { + return config['HooksController']; + } +}; \ No newline at end of file diff --git a/lib/browser/EventEmitter.js b/lib/browser/EventEmitter.js new file mode 100644 index 000000000..e9414f0bf --- /dev/null +++ b/lib/browser/EventEmitter.js @@ -0,0 +1,15 @@ +'use strict'; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * This is a simple wrapper to unify EventEmitter implementations across platforms. + */ + +module.exports = require('events').EventEmitter; +var EventEmitter; \ No newline at end of file diff --git a/lib/browser/FacebookUtils.js b/lib/browser/FacebookUtils.js new file mode 100644 index 000000000..bb8b7ef51 --- /dev/null +++ b/lib/browser/FacebookUtils.js @@ -0,0 +1,243 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _parseDate = require('./parseDate'); + +var _parseDate2 = _interopRequireDefault(_parseDate); + +var _ParseUser = require('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * -weak + */ + +var PUBLIC_KEY = "*"; + +var initialized = false; +var requestedPermissions; +var initOptions; +var provider = { + authenticate: function (options) { + var _this = this; + + if (typeof FB === 'undefined') { + options.error(this, 'Facebook SDK not found.'); + } + FB.login(function (response) { + if (response.authResponse) { + if (options.success) { + options.success(_this, { + id: response.authResponse.userID, + access_token: response.authResponse.accessToken, + expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() + }); + } + } else { + if (options.error) { + options.error(_this, response); + } + } + }, { + scope: requestedPermissions + }); + }, + restoreAuthentication: function (authData) { + if (authData) { + var expiration = (0, _parseDate2.default)(authData.expiration_date); + var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; + + var authResponse = { + userID: authData.id, + accessToken: authData.access_token, + expiresIn: expiresIn + }; + var newOptions = {}; + if (initOptions) { + for (var key in initOptions) { + newOptions[key] = initOptions[key]; + } + } + newOptions.authResponse = authResponse; + + // Suppress checks for login status from the browser. + newOptions.status = false; + + // If the user doesn't match the one known by the FB SDK, log out. + // Most of the time, the users will match -- it's only in cases where + // the FB SDK knows of a different user than the one being restored + // from a Parse User that logged in with username/password. + var existingResponse = FB.getAuthResponse(); + if (existingResponse && existingResponse.userID !== authResponse.userID) { + FB.logout(); + } + + FB.init(newOptions); + } + return true; + }, + getAuthType: function () { + return 'facebook'; + }, + deauthenticate: function () { + this.restoreAuthentication(null); + } +}; + +/** + * Provides a set of utilities for using Parse with Facebook. + * @class Parse.FacebookUtils + * @static + */ +var FacebookUtils = { + /** + * Initializes Parse Facebook integration. Call this function after you + * have loaded the Facebook Javascript SDK with the same parameters + * as you would pass to + * + * FB.init(). Parse.FacebookUtils will invoke FB.init() for you + * with these arguments. + * + * @method init + * @param {Object} options Facebook options argument as described here: + * + * FB.init(). The status flag will be coerced to 'false' because it + * interferes with Parse Facebook integration. Call FB.getLoginStatus() + * explicitly if this behavior is required by your application. + */ + init: function (options) { + if (typeof FB === 'undefined') { + throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); + } + initOptions = {}; + if (options) { + for (var key in options) { + initOptions[key] = options[key]; + } + } + if (initOptions.status && typeof console !== 'undefined') { + var warn = console.warn || console.log || function () {}; + warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); + } + initOptions.status = false; + FB.init(initOptions); + _ParseUser2.default._registerAuthenticationProvider(provider); + initialized = true; + }, + + /** + * Gets whether the user has their account linked to Facebook. + * + * @method isLinked + * @param {Parse.User} user User to check for a facebook link. + * The user must be logged in on this device. + * @return {Boolean} true if the user has their account + * linked to Facebook. + */ + isLinked: function (user) { + return user._isLinked('facebook'); + }, + + /** + * Logs in a user using Facebook. This method delegates to the Facebook + * SDK to authenticate the user, and then automatically logs in (or + * creates, in the case where it is a new user) a Parse.User. + * + * @method logIn + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + logIn: function (permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling logIn.'); + } + requestedPermissions = permissions; + return _ParseUser2.default._logInWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return _ParseUser2.default._logInWith('facebook', newOptions); + } + }, + + /** + * Links Facebook to an existing PFUser. This method delegates to the + * Facebook SDK to authenticate the user, and then automatically links + * the account to the Parse.User. + * + * @method link + * @param {Parse.User} user User to link to Facebook. This must be the + * current user. + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + link: function (user, permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling link.'); + } + requestedPermissions = permissions; + return user._linkWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return user._linkWith('facebook', newOptions); + } + }, + + /** + * Unlinks the Parse.User from a Facebook account. + * + * @method unlink + * @param {Parse.User} user User to unlink from Facebook. This must be the + * current user. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + unlink: function (user, options) { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling unlink.'); + } + return user._unlinkFrom('facebook', options); + } +}; + +exports.default = FacebookUtils; \ No newline at end of file diff --git a/lib/browser/InstallationController.js b/lib/browser/InstallationController.js new file mode 100644 index 000000000..7b01e3cad --- /dev/null +++ b/lib/browser/InstallationController.js @@ -0,0 +1,64 @@ +'use strict'; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var iidCache = null; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function hexOctet() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); +} + +function generateId() { + return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); +} + +var InstallationController = { + currentInstallationId: function () { + if (typeof iidCache === 'string') { + return _ParsePromise2.default.as(iidCache); + } + var path = _Storage2.default.generatePath('installationId'); + return _Storage2.default.getItemAsync(path).then(function (iid) { + if (!iid) { + iid = generateId(); + return _Storage2.default.setItemAsync(path, iid).then(function () { + iidCache = iid; + return iid; + }); + } + iidCache = iid; + return iid; + }); + }, + _clearCache: function () { + iidCache = null; + }, + _setInstallationIdCache: function (iid) { + iidCache = iid; + } +}; + +module.exports = InstallationController; \ No newline at end of file diff --git a/lib/browser/LiveQueryClient.js b/lib/browser/LiveQueryClient.js new file mode 100644 index 000000000..bc9603a62 --- /dev/null +++ b/lib/browser/LiveQueryClient.js @@ -0,0 +1,595 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getIterator2 = require('babel-runtime/core-js/get-iterator'); + +var _getIterator3 = _interopRequireDefault(_getIterator2); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _map = require('babel-runtime/core-js/map'); + +var _map2 = _interopRequireDefault(_map); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _EventEmitter2 = require('./EventEmitter'); + +var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _LiveQuerySubscription = require('./LiveQuerySubscription'); + +var _LiveQuerySubscription2 = _interopRequireDefault(_LiveQuerySubscription); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +// The LiveQuery client inner state +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +var CLIENT_STATE = { + INITIALIZED: 'initialized', + CONNECTING: 'connecting', + CONNECTED: 'connected', + CLOSED: 'closed', + RECONNECTING: 'reconnecting', + DISCONNECTED: 'disconnected' +}; + +// The event type the LiveQuery client should sent to server +var OP_TYPES = { + CONNECT: 'connect', + SUBSCRIBE: 'subscribe', + UNSUBSCRIBE: 'unsubscribe', + ERROR: 'error' +}; + +// The event we get back from LiveQuery server +var OP_EVENTS = { + CONNECTED: 'connected', + SUBSCRIBED: 'subscribed', + UNSUBSCRIBED: 'unsubscribed', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +// The event the LiveQuery client should emit +var CLIENT_EMMITER_TYPES = { + CLOSE: 'close', + ERROR: 'error', + OPEN: 'open' +}; + +// The event the LiveQuery subscription should emit +var SUBSCRIPTION_EMMITER_TYPES = { + OPEN: 'open', + CLOSE: 'close', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +var generateInterval = function (k) { + return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; +}; + +/** + * Creates a new LiveQueryClient. + * Extends events.EventEmitter + * cloud functions. + * + * A wrapper of a standard WebSocket client. We add several useful methods to + * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. + * + * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries + * to connect to the LiveQuery server + * + * @class Parse.LiveQueryClient + * @constructor + * @param {Object} options + * @param {string} options.applicationId - applicationId of your Parse app + * @param {string} options.serverURL - the URL of your LiveQuery server + * @param {string} options.javascriptKey (optional) + * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) + * @param {string} options.sessionToken (optional) + * + * + * We expose three events to help you monitor the status of the LiveQueryClient. + * + *
      + * let Parse = require('parse/node');
      + * let LiveQueryClient = Parse.LiveQueryClient;
      + * let client = new LiveQueryClient({
      + *   applicationId: '',
      + *   serverURL: '',
      + *   javascriptKey: '',
      + *   masterKey: ''
      + *  });
      + * 
      + * + * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + *
      + * client.on('open', () => {
      + * 
      + * });
      + * + * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + *
      + * client.on('close', () => {
      + * 
      + * });
      + * + * Error - When some network error or LiveQuery server error happens, you'll get this event. + *
      + * client.on('error', (error) => {
      + * 
      + * });
      + * + * + */ + +var LiveQueryClient = function (_EventEmitter) { + (0, _inherits3.default)(LiveQueryClient, _EventEmitter); + + function LiveQueryClient(_ref) { + var applicationId = _ref.applicationId, + serverURL = _ref.serverURL, + javascriptKey = _ref.javascriptKey, + masterKey = _ref.masterKey, + sessionToken = _ref.sessionToken; + (0, _classCallCheck3.default)(this, LiveQueryClient); + + var _this = (0, _possibleConstructorReturn3.default)(this, (LiveQueryClient.__proto__ || (0, _getPrototypeOf2.default)(LiveQueryClient)).call(this)); + + if (!serverURL || serverURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + _this.reconnectHandle = null; + _this.attempts = 1;; + _this.id = 0; + _this.requestId = 1; + _this.serverURL = serverURL; + _this.applicationId = applicationId; + _this.javascriptKey = javascriptKey; + _this.masterKey = masterKey; + _this.sessionToken = sessionToken; + _this.connectPromise = new _ParsePromise2.default(); + _this.subscriptions = new _map2.default(); + _this.state = CLIENT_STATE.INITIALIZED; + return _this; + } + + (0, _createClass3.default)(LiveQueryClient, [{ + key: 'shouldOpen', + value: function () { + return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; + } + + /** + * Subscribes to a ParseQuery + * + * If you provide the sessionToken, when the LiveQuery server gets ParseObject's + * updates from parse server, it'll try to check whether the sessionToken fulfills + * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose + * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol + * here for more details. The subscription you get is the same subscription you get + * from our Standard API. + * + * @method subscribe + * @param {Object} query - the ParseQuery you want to subscribe to + * @param {string} sessionToken (optional) + * @return {Object} subscription + */ + + }, { + key: 'subscribe', + value: function (query, sessionToken) { + var _this2 = this; + + if (!query) { + return; + } + var where = query.toJSON().where; + var className = query.className; + var subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: this.requestId, + query: { + className: className, + where: where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + var subscription = new _LiveQuerySubscription2.default(this.requestId, query, sessionToken); + this.subscriptions.set(this.requestId, subscription); + this.requestId += 1; + this.connectPromise.then(function () { + _this2.socket.send((0, _stringify2.default)(subscribeRequest)); + }); + + // adding listener so process does not crash + // best practice is for developer to register their own listener + subscription.on('error', function () {}); + + return subscription; + } + + /** + * After calling unsubscribe you'll stop receiving events from the subscription object. + * + * @method unsubscribe + * @param {Object} subscription - subscription you would like to unsubscribe from. + */ + + }, { + key: 'unsubscribe', + value: function (subscription) { + var _this3 = this; + + if (!subscription) { + return; + } + + this.subscriptions.delete(subscription.id); + var unsubscribeRequest = { + op: OP_TYPES.UNSUBSCRIBE, + requestId: subscription.id + }; + this.connectPromise.then(function () { + _this3.socket.send((0, _stringify2.default)(unsubscribeRequest)); + }); + } + + /** + * After open is called, the LiveQueryClient will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ + + }, { + key: 'open', + value: function () { + var _this4 = this; + + var WebSocketImplementation = this._getWebSocketImplementation(); + if (!WebSocketImplementation) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); + return; + } + + if (this.state !== CLIENT_STATE.RECONNECTING) { + this.state = CLIENT_STATE.CONNECTING; + } + + // Get WebSocket implementation + this.socket = new WebSocketImplementation(this.serverURL); + + // Bind WebSocket callbacks + this.socket.onopen = function () { + _this4._handleWebSocketOpen(); + }; + + this.socket.onmessage = function (event) { + _this4._handleWebSocketMessage(event); + }; + + this.socket.onclose = function () { + _this4._handleWebSocketClose(); + }; + + this.socket.onerror = function (error) { + _this4._handleWebSocketError(error); + }; + } + }, { + key: 'resubscribe', + value: function () { + var _this5 = this; + + this.subscriptions.forEach(function (subscription, requestId) { + var query = subscription.query; + var where = query.toJSON().where; + var className = query.className; + var sessionToken = subscription.sessionToken; + var subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: requestId, + query: { + className: className, + where: where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + _this5.connectPromise.then(function () { + _this5.socket.send((0, _stringify2.default)(subscribeRequest)); + }); + }); + } + + /** + * This method will close the WebSocket connection to this LiveQueryClient, + * cancel the auto reconnect and unsubscribe all subscriptions based on it. + * + * @method close + */ + + }, { + key: 'close', + value: function () { + if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.DISCONNECTED; + this.socket.close(); + // Notify each subscription about the close + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = (0, _getIterator3.default)(this.subscriptions.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var subscription = _step.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + this._handleReset(); + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + } + }, { + key: '_getWebSocketImplementation', + value: function () { + return typeof WebSocket === 'function' || (typeof WebSocket === 'undefined' ? 'undefined' : (0, _typeof3.default)(WebSocket)) === 'object' ? WebSocket : null; + } + + // ensure we start with valid state if connect is called again after close + + }, { + key: '_handleReset', + value: function () { + this.attempts = 1;; + this.id = 0; + this.requestId = 1; + this.connectPromise = new _ParsePromise2.default(); + this.subscriptions = new _map2.default(); + } + }, { + key: '_handleWebSocketOpen', + value: function () { + this.attempts = 1; + var connectRequest = { + op: OP_TYPES.CONNECT, + applicationId: this.applicationId, + javascriptKey: this.javascriptKey, + masterKey: this.masterKey, + sessionToken: this.sessionToken + }; + this.socket.send((0, _stringify2.default)(connectRequest)); + } + }, { + key: '_handleWebSocketMessage', + value: function (event) { + var data = event.data; + if (typeof data === 'string') { + data = JSON.parse(data); + } + var subscription = null; + if (data.requestId) { + subscription = this.subscriptions.get(data.requestId); + } + switch (data.op) { + case OP_EVENTS.CONNECTED: + if (this.state === CLIENT_STATE.RECONNECTING) { + this.resubscribe(); + } + this.emit(CLIENT_EMMITER_TYPES.OPEN); + this.id = data.clientId; + this.connectPromise.resolve(); + this.state = CLIENT_STATE.CONNECTED; + break; + case OP_EVENTS.SUBSCRIBED: + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); + } + break; + case OP_EVENTS.ERROR: + if (data.requestId) { + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); + } + } else { + this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); + } + break; + case OP_EVENTS.UNSUBSCRIBED: + // We have already deleted subscription in unsubscribe(), do nothing here + break; + default: + // create, update, enter, leave, delete cases + var className = data.object.className; + // Delete the extrea __type and className fields during transfer to full JSON + delete data.object.__type; + delete data.object.className; + var parseObject = new _ParseObject2.default(className); + parseObject._finishFetch(data.object); + if (!subscription) { + break; + } + subscription.emit(data.op, parseObject); + } + } + }, { + key: '_handleWebSocketClose', + value: function () { + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.CLOSED; + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + // Notify each subscription about the close + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = (0, _getIterator3.default)(this.subscriptions.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var subscription = _step2.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + this._handleReconnect(); + } + }, { + key: '_handleWebSocketError', + value: function (error) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, error); + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = (0, _getIterator3.default)(this.subscriptions.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var subscription = _step3.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + this._handleReconnect(); + } + }, { + key: '_handleReconnect', + value: function () { + var _this6 = this; + + // if closed or currently reconnecting we stop attempting to reconnect + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + + this.state = CLIENT_STATE.RECONNECTING; + var time = generateInterval(this.attempts); + + // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. + // we're unable to distinguish different between close/error when we're unable to reconnect therefore + // we try to reonnect in both cases + // server side ws and browser WebSocket behave differently in when close/error get triggered + + if (this.reconnectHandle) { + clearTimeout(this.reconnectHandle); + } + + this.reconnectHandle = setTimeout(function () { + _this6.attempts++; + _this6.connectPromise = new _ParsePromise2.default(); + _this6.open(); + }.bind(this), time); + } + }]); + return LiveQueryClient; +}(_EventEmitter3.default); + +exports.default = LiveQueryClient; \ No newline at end of file diff --git a/lib/browser/LiveQuerySubscription.js b/lib/browser/LiveQuerySubscription.js new file mode 100644 index 000000000..4078b65d5 --- /dev/null +++ b/lib/browser/LiveQuerySubscription.js @@ -0,0 +1,162 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _EventEmitter2 = require('./EventEmitter'); + +var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new LiveQuery Subscription. + * Extends events.EventEmitter + * cloud functions. + * + * @constructor + * @param {string} id - subscription id + * @param {string} query - query to subscribe to + * @param {string} sessionToken - optional session token + * + *

      Open Event - When you call query.subscribe(), we send a subscribe request to + * the LiveQuery server, when we get the confirmation from the LiveQuery server, + * this event will be emitted. When the client loses WebSocket connection to the + * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we + * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, + * you'll also get this event. + * + *

      + * subscription.on('open', () => {
      + * 
      + * });

      + * + *

      Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, + * you'll get this event. The object is the ParseObject which is created. + * + *

      + * subscription.on('create', (object) => {
      + * 
      + * });

      + * + *

      Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe + * is updated (The ParseObject fulfills the ParseQuery before and after changes), + * you'll get this event. The object is the ParseObject which is updated. + * Its content is the latest value of the ParseObject. + * + *

      + * subscription.on('update', (object) => {
      + * 
      + * });

      + * + *

      Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery + * but its new value fulfills the ParseQuery, you'll get this event. The object is the + * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. + * + *

      + * subscription.on('enter', (object) => {
      + * 
      + * });

      + * + * + *

      Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value + * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject + * which leaves the ParseQuery. Its content is the latest value of the ParseObject. + * + *

      + * subscription.on('leave', (object) => {
      + * 
      + * });

      + * + * + *

      Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll + * get this event. The object is the ParseObject which is deleted. + * + *

      + * subscription.on('delete', (object) => {
      + * 
      + * });

      + * + * + *

      Close Event - When the client loses the WebSocket connection to the LiveQuery + * server and we stop receiving events, you'll get this event. + * + *

      + * subscription.on('close', () => {
      + * 
      + * });

      + * + * + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +var Subscription = function (_EventEmitter) { + (0, _inherits3.default)(Subscription, _EventEmitter); + + function Subscription(id, query, sessionToken) { + (0, _classCallCheck3.default)(this, Subscription); + + var _this2 = (0, _possibleConstructorReturn3.default)(this, (Subscription.__proto__ || (0, _getPrototypeOf2.default)(Subscription)).call(this)); + + _this2.id = id; + _this2.query = query; + _this2.sessionToken = sessionToken; + return _this2; + } + + /** + * @method unsubscribe + */ + + (0, _createClass3.default)(Subscription, [{ + key: 'unsubscribe', + value: function () { + var _this3 = this; + + var _this = this; + _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient().then(function (liveQueryClient) { + liveQueryClient.unsubscribe(_this); + _this.emit('close'); + _this3.resolve(); + }); + } + }]); + return Subscription; +}(_EventEmitter3.default); + +exports.default = Subscription; \ No newline at end of file diff --git a/lib/browser/ObjectStateMutations.js b/lib/browser/ObjectStateMutations.js new file mode 100644 index 000000000..b476a0e2f --- /dev/null +++ b/lib/browser/ObjectStateMutations.js @@ -0,0 +1,165 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.defaultState = defaultState; +exports.setServerData = setServerData; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _TaskQueue = require('./TaskQueue'); + +var _TaskQueue2 = _interopRequireDefault(_TaskQueue); + +var _ParseOp = require('./ParseOp'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function defaultState() { + return { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new _TaskQueue2.default(), + existed: false + }; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function setServerData(serverData, attributes) { + for (var _attr in attributes) { + if (typeof attributes[_attr] !== 'undefined') { + serverData[_attr] = attributes[_attr]; + } else { + delete serverData[_attr]; + } + } +} + +function setPendingOp(pendingOps, attr, op) { + var last = pendingOps.length - 1; + if (op) { + pendingOps[last][attr] = op; + } else { + delete pendingOps[last][attr]; + } +} + +function pushPendingState(pendingOps) { + pendingOps.push({}); +} + +function popPendingState(pendingOps) { + var first = pendingOps.shift(); + if (!pendingOps.length) { + pendingOps[0] = {}; + } + return first; +} + +function mergeFirstPendingState(pendingOps) { + var first = popPendingState(pendingOps); + var next = pendingOps[0]; + for (var _attr2 in first) { + if (next[_attr2] && first[_attr2]) { + var merged = next[_attr2].mergeWith(first[_attr2]); + if (merged) { + next[_attr2] = merged; + } + } else { + next[_attr2] = first[_attr2]; + } + } +} + +function estimateAttribute(serverData, pendingOps, className, id, attr) { + var value = serverData[attr]; + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i][attr]) { + if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { + if (id) { + value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); + } + } else { + value = pendingOps[i][attr].applyTo(value); + } + } + } + return value; +} + +function estimateAttributes(serverData, pendingOps, className, id) { + var data = {}; + var attr = void 0; + for (attr in serverData) { + data[attr] = serverData[attr]; + } + for (var i = 0; i < pendingOps.length; i++) { + for (attr in pendingOps[i]) { + if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { + if (id) { + data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); + } + } else { + data[attr] = pendingOps[i][attr].applyTo(data[attr]); + } + } + } + return data; +} + +function commitServerChanges(serverData, objectCache, changes) { + for (var _attr3 in changes) { + var val = changes[_attr3]; + serverData[_attr3] = val; + if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof _ParseObject2.default) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { + var json = (0, _encode2.default)(val, false, true); + objectCache[_attr3] = (0, _stringify2.default)(json); + } + } +} \ No newline at end of file diff --git a/lib/browser/Parse.js b/lib/browser/Parse.js new file mode 100644 index 000000000..2499dc786 --- /dev/null +++ b/lib/browser/Parse.js @@ -0,0 +1,186 @@ +'use strict'; + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _InstallationController = require('./InstallationController'); + +var _InstallationController2 = _interopRequireDefault(_InstallationController); + +var _ParseOp = require('./ParseOp'); + +var ParseOp = _interopRequireWildcard(_ParseOp); + +var _RESTController = require('./RESTController'); + +var _RESTController2 = _interopRequireDefault(_RESTController); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains all Parse API classes and functions. + * @class Parse + * @static + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var Parse = { + /** + * Call this method first to set up your authentication tokens for Parse. + * You can get your keys from the Data Browser on parse.com. + * @method initialize + * @param {String} applicationId Your Parse Application ID. + * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) + * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) + * @static + */ + initialize: function (applicationId, javaScriptKey) { + if ('browser' === 'browser' && _CoreManager2.default.get('IS_NODE')) { + console.log('It looks like you\'re using the browser version of the SDK in a ' + 'node.js environment. You should require(\'parse/node\') instead.'); + } + Parse._initialize(applicationId, javaScriptKey); + }, + _initialize: function (applicationId, javaScriptKey, masterKey) { + _CoreManager2.default.set('APPLICATION_ID', applicationId); + _CoreManager2.default.set('JAVASCRIPT_KEY', javaScriptKey); + _CoreManager2.default.set('MASTER_KEY', masterKey); + _CoreManager2.default.set('USE_MASTER_KEY', false); + } +}; + +/** These legacy setters may eventually be deprecated **/ +Object.defineProperty(Parse, 'applicationId', { + get: function () { + return _CoreManager2.default.get('APPLICATION_ID'); + }, + set: function (value) { + _CoreManager2.default.set('APPLICATION_ID', value); + } +}); +Object.defineProperty(Parse, 'javaScriptKey', { + get: function () { + return _CoreManager2.default.get('JAVASCRIPT_KEY'); + }, + set: function (value) { + _CoreManager2.default.set('JAVASCRIPT_KEY', value); + } +}); +Object.defineProperty(Parse, 'masterKey', { + get: function () { + return _CoreManager2.default.get('MASTER_KEY'); + }, + set: function (value) { + _CoreManager2.default.set('MASTER_KEY', value); + } +}); +Object.defineProperty(Parse, 'serverURL', { + get: function () { + return _CoreManager2.default.get('SERVER_URL'); + }, + set: function (value) { + _CoreManager2.default.set('SERVER_URL', value); + } +}); +Object.defineProperty(Parse, 'liveQueryServerURL', { + get: function () { + return _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); + }, + set: function (value) { + _CoreManager2.default.set('LIVEQUERY_SERVER_URL', value); + } +}); +/** End setters **/ + +Parse.ACL = require('./ParseACL').default; +Parse.Analytics = require('./Analytics'); +Parse.Cloud = require('./Cloud'); +Parse.CoreManager = require('./CoreManager'); +Parse.Config = require('./ParseConfig').default; +Parse.Error = require('./ParseError').default; +Parse.FacebookUtils = require('./FacebookUtils').default; +Parse.File = require('./ParseFile').default; +Parse.GeoPoint = require('./ParseGeoPoint').default; +Parse.Installation = require('./ParseInstallation').default; +Parse.Object = require('./ParseObject').default; +Parse.Op = { + Set: ParseOp.SetOp, + Unset: ParseOp.UnsetOp, + Increment: ParseOp.IncrementOp, + Add: ParseOp.AddOp, + Remove: ParseOp.RemoveOp, + AddUnique: ParseOp.AddUniqueOp, + Relation: ParseOp.RelationOp +}; +Parse.Promise = require('./ParsePromise').default; +Parse.Push = require('./Push'); +Parse.Query = require('./ParseQuery').default; +Parse.Relation = require('./ParseRelation').default; +Parse.Role = require('./ParseRole').default; +Parse.Session = require('./ParseSession').default; +Parse.Storage = require('./Storage'); +Parse.User = require('./ParseUser').default; +Parse.LiveQuery = require('./ParseLiveQuery').default; +Parse.LiveQueryClient = require('./LiveQueryClient').default; + +Parse._request = function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return _CoreManager2.default.getRESTController().request.apply(null, args); +}; +Parse._ajax = function () { + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return _CoreManager2.default.getRESTController().ajax.apply(null, args); +}; +// We attempt to match the signatures of the legacy versions of these methods +Parse._decode = function (_, value) { + return (0, _decode2.default)(value); +}; +Parse._encode = function (value, _, disallowObjects) { + return (0, _encode2.default)(value, disallowObjects); +}; +Parse._getInstallationId = function () { + return _CoreManager2.default.getInstallationController().currentInstallationId(); +}; + +_CoreManager2.default.setInstallationController(_InstallationController2.default); +_CoreManager2.default.setRESTController(_RESTController2.default); + +// For legacy requires, of the form `var Parse = require('parse').Parse` +Parse.Parse = Parse; + +module.exports = Parse; \ No newline at end of file diff --git a/lib/browser/ParseACL.js b/lib/browser/ParseACL.js new file mode 100644 index 000000000..2aa232c18 --- /dev/null +++ b/lib/browser/ParseACL.js @@ -0,0 +1,406 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParseRole = require('./ParseRole'); + +var _ParseRole2 = _interopRequireDefault(_ParseRole); + +var _ParseUser = require('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var PUBLIC_KEY = '*'; + +/** + * Creates a new ACL. + * If no argument is given, the ACL has no permissions for anyone. + * If the argument is a Parse.User, the ACL will have read and write + * permission for only that user. + * If the argument is any other JSON object, that object will be interpretted + * as a serialized ACL created with toJSON(). + * @class Parse.ACL + * @constructor + * + *

      An ACL, or Access Control List can be added to any + * Parse.Object to restrict access to only a subset of users + * of your application.

      + */ + +var ParseACL = function () { + function ParseACL(arg1) { + (0, _classCallCheck3.default)(this, ParseACL); + + this.permissionsById = {}; + if (arg1 && (typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { + if (arg1 instanceof _ParseUser2.default) { + this.setReadAccess(arg1, true); + this.setWriteAccess(arg1, true); + } else { + for (var userId in arg1) { + var accessList = arg1[userId]; + if (typeof userId !== 'string') { + throw new TypeError('Tried to create an ACL with an invalid user id.'); + } + this.permissionsById[userId] = {}; + for (var permission in accessList) { + var allowed = accessList[permission]; + if (permission !== 'read' && permission !== 'write') { + throw new TypeError('Tried to create an ACL with an invalid permission type.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('Tried to create an ACL with an invalid permission value.'); + } + this.permissionsById[userId][permission] = allowed; + } + } + } + } else if (typeof arg1 === 'function') { + throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); + } + } + + /** + * Returns a JSON-encoded version of the ACL. + * @method toJSON + * @return {Object} + */ + + (0, _createClass3.default)(ParseACL, [{ + key: 'toJSON', + value: function () { + var permissions = {}; + for (var p in this.permissionsById) { + permissions[p] = this.permissionsById[p]; + } + return permissions; + } + + /** + * Returns whether this ACL is equal to another object + * @method equals + * @param other The other object to compare to + * @return {Boolean} + */ + + }, { + key: 'equals', + value: function (other) { + if (!(other instanceof ParseACL)) { + return false; + } + var users = (0, _keys2.default)(this.permissionsById); + var otherUsers = (0, _keys2.default)(other.permissionsById); + if (users.length !== otherUsers.length) { + return false; + } + for (var u in this.permissionsById) { + if (!other.permissionsById[u]) { + return false; + } + if (this.permissionsById[u].read !== other.permissionsById[u].read) { + return false; + } + if (this.permissionsById[u].write !== other.permissionsById[u].write) { + return false; + } + } + return true; + } + }, { + key: '_setAccess', + value: function (accessType, userId, allowed) { + if (userId instanceof _ParseUser2.default) { + userId = userId.id; + } else if (userId instanceof _ParseRole2.default) { + var name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + if (typeof userId !== 'string') { + throw new TypeError('userId must be a string.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('allowed must be either true or false.'); + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + if (!allowed) { + // The user already doesn't have this permission, so no action is needed + return; + } else { + permissions = {}; + this.permissionsById[userId] = permissions; + } + } + + if (allowed) { + this.permissionsById[userId][accessType] = true; + } else { + delete permissions[accessType]; + if ((0, _keys2.default)(permissions).length === 0) { + delete this.permissionsById[userId]; + } + } + } + }, { + key: '_getAccess', + value: function (accessType, userId) { + if (userId instanceof _ParseUser2.default) { + userId = userId.id; + if (!userId) { + throw new Error('Cannot get access for a ParseUser without an ID'); + } + } else if (userId instanceof _ParseRole2.default) { + var name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + return false; + } + return !!permissions[accessType]; + } + + /** + * Sets whether the given user is allowed to read this object. + * @method setReadAccess + * @param userId An instance of Parse.User or its objectId. + * @param {Boolean} allowed Whether that user should have read access. + */ + + }, { + key: 'setReadAccess', + value: function (userId, allowed) { + this._setAccess('read', userId, allowed); + } + + /** + * Get whether the given user id is *explicitly* allowed to read this object. + * Even if this returns false, the user may still be able to access it if + * getPublicReadAccess returns true or a role that the user belongs to has + * write access. + * @method getReadAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + + }, { + key: 'getReadAccess', + value: function (userId) { + return this._getAccess('read', userId); + } + + /** + * Sets whether the given user id is allowed to write this object. + * @method setWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. + * @param {Boolean} allowed Whether that user should have write access. + */ + + }, { + key: 'setWriteAccess', + value: function (userId, allowed) { + this._setAccess('write', userId, allowed); + } + + /** + * Gets whether the given user id is *explicitly* allowed to write this object. + * Even if this returns false, the user may still be able to write it if + * getPublicWriteAccess returns true or a role that the user belongs to has + * write access. + * @method getWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + + }, { + key: 'getWriteAccess', + value: function (userId) { + return this._getAccess('write', userId); + } + + /** + * Sets whether the public is allowed to read this object. + * @method setPublicReadAccess + * @param {Boolean} allowed + */ + + }, { + key: 'setPublicReadAccess', + value: function (allowed) { + this.setReadAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to read this object. + * @method getPublicReadAccess + * @return {Boolean} + */ + + }, { + key: 'getPublicReadAccess', + value: function () { + return this.getReadAccess(PUBLIC_KEY); + } + + /** + * Sets whether the public is allowed to write this object. + * @method setPublicWriteAccess + * @param {Boolean} allowed + */ + + }, { + key: 'setPublicWriteAccess', + value: function (allowed) { + this.setWriteAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to write this object. + * @method getPublicWriteAccess + * @return {Boolean} + */ + + }, { + key: 'getPublicWriteAccess', + value: function () { + return this.getWriteAccess(PUBLIC_KEY); + } + + /** + * Gets whether users belonging to the given role are allowed + * to read this object. Even if this returns false, the role may + * still be able to write it if a parent role has read access. + * + * @method getRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has read access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'getRoleReadAccess', + value: function (role) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getReadAccess('role:' + role); + } + + /** + * Gets whether users belonging to the given role are allowed + * to write this object. Even if this returns false, the role may + * still be able to write it if a parent role has write access. + * + * @method getRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has write access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'getRoleWriteAccess', + value: function (role) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getWriteAccess('role:' + role); + } + + /** + * Sets whether users belonging to the given role are allowed + * to read this object. + * + * @method setRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can read this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'setRoleReadAccess', + value: function (role, allowed) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setReadAccess('role:' + role, allowed); + } + + /** + * Sets whether users belonging to the given role are allowed + * to write this object. + * + * @method setRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can write this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'setRoleWriteAccess', + value: function (role, allowed) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setWriteAccess('role:' + role, allowed); + } + }]); + return ParseACL; +}(); + +exports.default = ParseACL; \ No newline at end of file diff --git a/lib/browser/ParseConfig.js b/lib/browser/ParseConfig.js new file mode 100644 index 000000000..925e3a864 --- /dev/null +++ b/lib/browser/ParseConfig.js @@ -0,0 +1,228 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _escape2 = require('./escape'); + +var _escape3 = _interopRequireDefault(_escape2); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Parse.Config is a local representation of configuration data that + * can be set from the Parse dashboard. + * + * @class Parse.Config + * @constructor + */ + +var ParseConfig = function () { + function ParseConfig() { + (0, _classCallCheck3.default)(this, ParseConfig); + + this.attributes = {}; + this._escapedAttributes = {}; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The name of an attribute. + */ + + (0, _createClass3.default)(ParseConfig, [{ + key: 'get', + value: function (attr) { + return this.attributes[attr]; + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The name of an attribute. + */ + + }, { + key: 'escape', + value: function (attr) { + var html = this._escapedAttributes[attr]; + if (html) { + return html; + } + var val = this.attributes[attr]; + var escaped = ''; + if (val != null) { + escaped = (0, _escape3.default)(val.toString()); + } + this._escapedAttributes[attr] = escaped; + return escaped; + } + + /** + * Retrieves the most recently-fetched configuration object, either from + * memory or from local storage if necessary. + * + * @method current + * @static + * @return {Config} The most recently-fetched Parse.Config if it + * exists, else an empty Parse.Config. + */ + + }], [{ + key: 'current', + value: function () { + var controller = _CoreManager2.default.getConfigController(); + return controller.current(); + } + + /** + * Gets a new configuration object from the server. + * @method get + * @static + * @param {Object} options A Backbone-style options object. + * Valid options are:
        + *
      • success: Function to call when the get completes successfully. + *
      • error: Function to call when the get fails. + *
      + * @return {Parse.Promise} A promise that is resolved with a newly-created + * configuration object when the get completes. + */ + + }, { + key: 'get', + value: function (options) { + options = options || {}; + + var controller = _CoreManager2.default.getConfigController(); + return controller.get()._thenRunCallbacks(options); + } + }]); + return ParseConfig; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseConfig; + +var currentConfig = null; + +var CURRENT_CONFIG_KEY = 'currentConfig'; + +function decodePayload(data) { + try { + var json = JSON.parse(data); + if (json && (typeof json === 'undefined' ? 'undefined' : (0, _typeof3.default)(json)) === 'object') { + return (0, _decode2.default)(json); + } + } catch (e) { + return null; + } +} + +var DefaultController = { + current: function () { + if (currentConfig) { + return currentConfig; + } + + var config = new ParseConfig(); + var storagePath = _Storage2.default.generatePath(CURRENT_CONFIG_KEY); + var configData; + if (!_Storage2.default.async()) { + configData = _Storage2.default.getItem(storagePath); + + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + } + // Return a promise for async storage controllers + return _Storage2.default.getItemAsync(storagePath).then(function (configData) { + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + }); + }, + get: function () { + var RESTController = _CoreManager2.default.getRESTController(); + + return RESTController.request('GET', 'config', {}, {}).then(function (response) { + if (!response || !response.params) { + var error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Config JSON response invalid.'); + return _ParsePromise2.default.error(error); + } + + var config = new ParseConfig(); + config.attributes = {}; + for (var attr in response.params) { + config.attributes[attr] = (0, _decode2.default)(response.params[attr]); + } + currentConfig = config; + return _Storage2.default.setItemAsync(_Storage2.default.generatePath(CURRENT_CONFIG_KEY), (0, _stringify2.default)(response.params)).then(function () { + return config; + }); + }); + } +}; + +_CoreManager2.default.setConfigController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseError.js b/lib/browser/ParseError.js new file mode 100644 index 000000000..b3bad4512 --- /dev/null +++ b/lib/browser/ParseError.js @@ -0,0 +1,507 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * Constructs a new Parse.Error object with the given code and message. + * @class Parse.Error + * @constructor + * @param {Number} code An error code constant from Parse.Error. + * @param {String} message A detailed description of the error. + */ +var ParseError = function ParseError(code, message) { + (0, _classCallCheck3.default)(this, ParseError); + + this.code = code; + this.message = message; +}; + +/** + * Error code indicating some error other than those enumerated here. + * @property OTHER_CAUSE + * @static + * @final + */ + +exports.default = ParseError; +ParseError.OTHER_CAUSE = -1; + +/** + * Error code indicating that something has gone wrong with the server. + * If you get this error code, it is Parse's fault. Contact us at + * https://parse.com/help + * @property INTERNAL_SERVER_ERROR + * @static + * @final + */ +ParseError.INTERNAL_SERVER_ERROR = 1; + +/** + * Error code indicating the connection to the Parse servers failed. + * @property CONNECTION_FAILED + * @static + * @final + */ +ParseError.CONNECTION_FAILED = 100; + +/** + * Error code indicating the specified object doesn't exist. + * @property OBJECT_NOT_FOUND + * @static + * @final + */ +ParseError.OBJECT_NOT_FOUND = 101; + +/** + * Error code indicating you tried to query with a datatype that doesn't + * support it, like exact matching an array or object. + * @property INVALID_QUERY + * @static + * @final + */ +ParseError.INVALID_QUERY = 102; + +/** + * Error code indicating a missing or invalid classname. Classnames are + * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the + * only valid characters. + * @property INVALID_CLASS_NAME + * @static + * @final + */ +ParseError.INVALID_CLASS_NAME = 103; + +/** + * Error code indicating an unspecified object id. + * @property MISSING_OBJECT_ID + * @static + * @final + */ +ParseError.MISSING_OBJECT_ID = 104; + +/** + * Error code indicating an invalid key name. Keys are case-sensitive. They + * must start with a letter, and a-zA-Z0-9_ are the only valid characters. + * @property INVALID_KEY_NAME + * @static + * @final + */ +ParseError.INVALID_KEY_NAME = 105; + +/** + * Error code indicating a malformed pointer. You should not see this unless + * you have been mucking about changing internal Parse code. + * @property INVALID_POINTER + * @static + * @final + */ +ParseError.INVALID_POINTER = 106; + +/** + * Error code indicating that badly formed JSON was received upstream. This + * either indicates you have done something unusual with modifying how + * things encode to JSON, or the network is failing badly. + * @property INVALID_JSON + * @static + * @final + */ +ParseError.INVALID_JSON = 107; + +/** + * Error code indicating that the feature you tried to access is only + * available internally for testing purposes. + * @property COMMAND_UNAVAILABLE + * @static + * @final + */ +ParseError.COMMAND_UNAVAILABLE = 108; + +/** + * You must call Parse.initialize before using the Parse library. + * @property NOT_INITIALIZED + * @static + * @final + */ +ParseError.NOT_INITIALIZED = 109; + +/** + * Error code indicating that a field was set to an inconsistent type. + * @property INCORRECT_TYPE + * @static + * @final + */ +ParseError.INCORRECT_TYPE = 111; + +/** + * Error code indicating an invalid channel name. A channel name is either + * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ + * characters and starts with a letter. + * @property INVALID_CHANNEL_NAME + * @static + * @final + */ +ParseError.INVALID_CHANNEL_NAME = 112; + +/** + * Error code indicating that push is misconfigured. + * @property PUSH_MISCONFIGURED + * @static + * @final + */ +ParseError.PUSH_MISCONFIGURED = 115; + +/** + * Error code indicating that the object is too large. + * @property OBJECT_TOO_LARGE + * @static + * @final + */ +ParseError.OBJECT_TOO_LARGE = 116; + +/** + * Error code indicating that the operation isn't allowed for clients. + * @property OPERATION_FORBIDDEN + * @static + * @final + */ +ParseError.OPERATION_FORBIDDEN = 119; + +/** + * Error code indicating the result was not found in the cache. + * @property CACHE_MISS + * @static + * @final + */ +ParseError.CACHE_MISS = 120; + +/** + * Error code indicating that an invalid key was used in a nested + * JSONObject. + * @property INVALID_NESTED_KEY + * @static + * @final + */ +ParseError.INVALID_NESTED_KEY = 121; + +/** + * Error code indicating that an invalid filename was used for ParseFile. + * A valid file name contains only a-zA-Z0-9_. characters and is between 1 + * and 128 characters. + * @property INVALID_FILE_NAME + * @static + * @final + */ +ParseError.INVALID_FILE_NAME = 122; + +/** + * Error code indicating an invalid ACL was provided. + * @property INVALID_ACL + * @static + * @final + */ +ParseError.INVALID_ACL = 123; + +/** + * Error code indicating that the request timed out on the server. Typically + * this indicates that the request is too expensive to run. + * @property TIMEOUT + * @static + * @final + */ +ParseError.TIMEOUT = 124; + +/** + * Error code indicating that the email address was invalid. + * @property INVALID_EMAIL_ADDRESS + * @static + * @final + */ +ParseError.INVALID_EMAIL_ADDRESS = 125; + +/** + * Error code indicating a missing content type. + * @property MISSING_CONTENT_TYPE + * @static + * @final + */ +ParseError.MISSING_CONTENT_TYPE = 126; + +/** + * Error code indicating a missing content length. + * @property MISSING_CONTENT_LENGTH + * @static + * @final + */ +ParseError.MISSING_CONTENT_LENGTH = 127; + +/** + * Error code indicating an invalid content length. + * @property INVALID_CONTENT_LENGTH + * @static + * @final + */ +ParseError.INVALID_CONTENT_LENGTH = 128; + +/** + * Error code indicating a file that was too large. + * @property FILE_TOO_LARGE + * @static + * @final + */ +ParseError.FILE_TOO_LARGE = 129; + +/** + * Error code indicating an error saving a file. + * @property FILE_SAVE_ERROR + * @static + * @final + */ +ParseError.FILE_SAVE_ERROR = 130; + +/** + * Error code indicating that a unique field was given a value that is + * already taken. + * @property DUPLICATE_VALUE + * @static + * @final + */ +ParseError.DUPLICATE_VALUE = 137; + +/** + * Error code indicating that a role's name is invalid. + * @property INVALID_ROLE_NAME + * @static + * @final + */ +ParseError.INVALID_ROLE_NAME = 139; + +/** + * Error code indicating that an application quota was exceeded. Upgrade to + * resolve. + * @property EXCEEDED_QUOTA + * @static + * @final + */ +ParseError.EXCEEDED_QUOTA = 140; + +/** + * Error code indicating that a Cloud Code script failed. + * @property SCRIPT_FAILED + * @static + * @final + */ +ParseError.SCRIPT_FAILED = 141; + +/** + * Error code indicating that a Cloud Code validation failed. + * @property VALIDATION_ERROR + * @static + * @final + */ +ParseError.VALIDATION_ERROR = 142; + +/** + * Error code indicating that invalid image data was provided. + * @property INVALID_IMAGE_DATA + * @static + * @final + */ +ParseError.INVALID_IMAGE_DATA = 143; + +/** + * Error code indicating an unsaved file. + * @property UNSAVED_FILE_ERROR + * @static + * @final + */ +ParseError.UNSAVED_FILE_ERROR = 151; + +/** + * Error code indicating an invalid push time. + * @property INVALID_PUSH_TIME_ERROR + * @static + * @final + */ +ParseError.INVALID_PUSH_TIME_ERROR = 152; + +/** + * Error code indicating an error deleting a file. + * @property FILE_DELETE_ERROR + * @static + * @final + */ +ParseError.FILE_DELETE_ERROR = 153; + +/** + * Error code indicating that the application has exceeded its request + * limit. + * @property REQUEST_LIMIT_EXCEEDED + * @static + * @final + */ +ParseError.REQUEST_LIMIT_EXCEEDED = 155; + +/** + * Error code indicating an invalid event name. + * @property INVALID_EVENT_NAME + * @static + * @final + */ +ParseError.INVALID_EVENT_NAME = 160; + +/** + * Error code indicating that the username is missing or empty. + * @property USERNAME_MISSING + * @static + * @final + */ +ParseError.USERNAME_MISSING = 200; + +/** + * Error code indicating that the password is missing or empty. + * @property PASSWORD_MISSING + * @static + * @final + */ +ParseError.PASSWORD_MISSING = 201; + +/** + * Error code indicating that the username has already been taken. + * @property USERNAME_TAKEN + * @static + * @final + */ +ParseError.USERNAME_TAKEN = 202; + +/** + * Error code indicating that the email has already been taken. + * @property EMAIL_TAKEN + * @static + * @final + */ +ParseError.EMAIL_TAKEN = 203; + +/** + * Error code indicating that the email is missing, but must be specified. + * @property EMAIL_MISSING + * @static + * @final + */ +ParseError.EMAIL_MISSING = 204; + +/** + * Error code indicating that a user with the specified email was not found. + * @property EMAIL_NOT_FOUND + * @static + * @final + */ +ParseError.EMAIL_NOT_FOUND = 205; + +/** + * Error code indicating that a user object without a valid session could + * not be altered. + * @property SESSION_MISSING + * @static + * @final + */ +ParseError.SESSION_MISSING = 206; + +/** + * Error code indicating that a user can only be created through signup. + * @property MUST_CREATE_USER_THROUGH_SIGNUP + * @static + * @final + */ +ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; + +/** + * Error code indicating that an an account being linked is already linked + * to another user. + * @property ACCOUNT_ALREADY_LINKED + * @static + * @final + */ +ParseError.ACCOUNT_ALREADY_LINKED = 208; + +/** + * Error code indicating that the current session token is invalid. + * @property INVALID_SESSION_TOKEN + * @static + * @final + */ +ParseError.INVALID_SESSION_TOKEN = 209; + +/** + * Error code indicating that a user cannot be linked to an account because + * that account's id could not be found. + * @property LINKED_ID_MISSING + * @static + * @final + */ +ParseError.LINKED_ID_MISSING = 250; + +/** + * Error code indicating that a user with a linked (e.g. Facebook) account + * has an invalid session. + * @property INVALID_LINKED_SESSION + * @static + * @final + */ +ParseError.INVALID_LINKED_SESSION = 251; + +/** + * Error code indicating that a service being linked (e.g. Facebook or + * Twitter) is unsupported. + * @property UNSUPPORTED_SERVICE + * @static + * @final + */ +ParseError.UNSUPPORTED_SERVICE = 252; + +/** + * Error code indicating that there were multiple errors. Aggregate errors + * have an "errors" property, which is an array of error objects with more + * detail about each error that occurred. + * @property AGGREGATE_ERROR + * @static + * @final + */ +ParseError.AGGREGATE_ERROR = 600; + +/** + * Error code indicating the client was unable to read an input file. + * @property FILE_READ_ERROR + * @static + * @final + */ +ParseError.FILE_READ_ERROR = 601; + +/** + * Error code indicating a real error code is unavailable because + * we had to use an XDomainRequest object to allow CORS requests in + * Internet Explorer, which strips the body from HTTP responses that have + * a non-2XX status code. + * @property X_DOMAIN_REQUEST + * @static + * @final + */ +ParseError.X_DOMAIN_REQUEST = 602; \ No newline at end of file diff --git a/lib/browser/ParseFile.js b/lib/browser/ParseFile.js new file mode 100644 index 000000000..48efdb9d8 --- /dev/null +++ b/lib/browser/ParseFile.js @@ -0,0 +1,291 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; + +function b64Digit(number) { + if (number < 26) { + return String.fromCharCode(65 + number); + } + if (number < 52) { + return String.fromCharCode(97 + (number - 26)); + } + if (number < 62) { + return String.fromCharCode(48 + (number - 52)); + } + if (number === 62) { + return '+'; + } + if (number === 63) { + return '/'; + } + throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); +} + +/** + * A Parse.File is a local representation of a file that is saved to the Parse + * cloud. + * @class Parse.File + * @constructor + * @param name {String} The file's name. This will be prefixed by a unique + * value once the file has finished saving. The file name must begin with + * an alphanumeric character, and consist of alphanumeric characters, + * periods, spaces, underscores, or dashes. + * @param data {Array} The data for the file, as either: + * 1. an Array of byte value Numbers, or + * 2. an Object like { base64: "..." } with a base64-encoded String. + * 3. a File object selected with a file upload control. (3) only works + * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. + * For example:
      + * var fileUploadControl = $("#profilePhotoFileUpload")[0];
      + * if (fileUploadControl.files.length > 0) {
      + *   var file = fileUploadControl.files[0];
      + *   var name = "photo.jpg";
      + *   var parseFile = new Parse.File(name, file);
      + *   parseFile.save().then(function() {
      + *     // The file has been saved to Parse.
      + *   }, function(error) {
      + *     // The file either could not be read, or could not be saved to Parse.
      + *   });
      + * }
      + * @param type {String} Optional Content-Type header to use for the file. If + * this is omitted, the content type will be inferred from the name's + * extension. + */ + +var ParseFile = function () { + function ParseFile(name, data, type) { + (0, _classCallCheck3.default)(this, ParseFile); + + var specifiedType = type || ''; + + this._name = name; + + if (data !== undefined) { + if (Array.isArray(data)) { + this._source = { + format: 'base64', + base64: ParseFile.encodeBase64(data), + type: specifiedType + }; + } else if (typeof File !== 'undefined' && data instanceof File) { + this._source = { + format: 'file', + file: data, + type: specifiedType + }; + } else if (data && typeof data.base64 === 'string') { + var _base = data.base64; + var commaIndex = _base.indexOf(','); + + if (commaIndex !== -1) { + var matches = dataUriRegexp.exec(_base.slice(0, commaIndex + 1)); + // if data URI with type and charset, there will be 4 matches. + this._source = { + format: 'base64', + base64: _base.slice(commaIndex + 1), + type: matches[1] + }; + } else { + this._source = { + format: 'base64', + base64: _base, + type: specifiedType + }; + } + } else { + throw new TypeError('Cannot create a Parse.File with that data.'); + } + } + } + + /** + * Gets the name of the file. Before save is called, this is the filename + * given by the user. After save is called, that name gets prefixed with a + * unique identifier. + * @method name + * @return {String} + */ + + (0, _createClass3.default)(ParseFile, [{ + key: 'name', + value: function () { + return this._name; + } + + /** + * Gets the url of the file. It is only available after you save the file or + * after you get the file from a Parse.Object. + * @method url + * @param {Object} options An object to specify url options + * @return {String} + */ + + }, { + key: 'url', + value: function (options) { + options = options || {}; + if (!this._url) { + return; + } + if (options.forceSecure) { + return this._url.replace(/^http:\/\//i, 'https://'); + } else { + return this._url; + } + } + + /** + * Saves the file to the Parse cloud. + * @method save + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} Promise that is resolved when the save finishes. + */ + + }, { + key: 'save', + value: function (options) { + var _this = this; + + options = options || {}; + var controller = _CoreManager2.default.getFileController(); + if (!this._previousSave) { + if (this._source.format === 'file') { + this._previousSave = controller.saveFile(this._name, this._source).then(function (res) { + _this._name = res.name; + _this._url = res.url; + return _this; + }); + } else { + this._previousSave = controller.saveBase64(this._name, this._source).then(function (res) { + _this._name = res.name; + _this._url = res.url; + return _this; + }); + } + } + if (this._previousSave) { + return this._previousSave._thenRunCallbacks(options); + } + } + }, { + key: 'toJSON', + value: function () { + return { + __type: 'File', + name: this._name, + url: this._url + }; + } + }, { + key: 'equals', + value: function (other) { + if (this === other) { + return true; + } + // Unsaved Files are never equal, since they will be saved to different URLs + return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; + } + }], [{ + key: 'fromJSON', + value: function (obj) { + if (obj.__type !== 'File') { + throw new TypeError('JSON object does not represent a ParseFile'); + } + var file = new ParseFile(obj.name); + file._url = obj.url; + return file; + } + }, { + key: 'encodeBase64', + value: function (bytes) { + var chunks = []; + chunks.length = Math.ceil(bytes.length / 3); + for (var i = 0; i < chunks.length; i++) { + var b1 = bytes[i * 3]; + var b2 = bytes[i * 3 + 1] || 0; + var b3 = bytes[i * 3 + 2] || 0; + + var has2 = i * 3 + 1 < bytes.length; + var has3 = i * 3 + 2 < bytes.length; + + chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); + } + + return chunks.join(''); + } + }]); + return ParseFile; +}(); + +exports.default = ParseFile; + +var DefaultController = { + saveFile: function (name, source) { + if (source.format !== 'file') { + throw new Error('saveFile can only be used with File-type sources.'); + } + // To directly upload a File, we use a REST-style AJAX request + var headers = { + 'X-Parse-Application-ID': _CoreManager2.default.get('APPLICATION_ID'), + 'X-Parse-JavaScript-Key': _CoreManager2.default.get('JAVASCRIPT_KEY'), + 'Content-Type': source.type || (source.file ? source.file.type : null) + }; + var url = _CoreManager2.default.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += 'files/' + name; + return _CoreManager2.default.getRESTController().ajax('POST', url, source.file, headers); + }, + + saveBase64: function (name, source) { + if (source.format !== 'base64') { + throw new Error('saveBase64 can only be used with Base64-type sources.'); + } + var data = { + base64: source.base64 + }; + if (source.type) { + data._ContentType = source.type; + } + + return _CoreManager2.default.getRESTController().request('POST', 'files/' + name, data); + } +}; + +_CoreManager2.default.setFileController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseGeoPoint.js b/lib/browser/ParseGeoPoint.js new file mode 100644 index 000000000..98691f85b --- /dev/null +++ b/lib/browser/ParseGeoPoint.js @@ -0,0 +1,235 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new GeoPoint with any of the following forms:
      + *
      + *   new GeoPoint(otherGeoPoint)
      + *   new GeoPoint(30, 30)
      + *   new GeoPoint([30, 30])
      + *   new GeoPoint({latitude: 30, longitude: 30})
      + *   new GeoPoint()  // defaults to (0, 0)
      + *   
      + * @class Parse.GeoPoint + * @constructor + * + *

      Represents a latitude / longitude point that may be associated + * with a key in a ParseObject or used as a reference point for geo queries. + * This allows proximity-based queries on the key.

      + * + *

      Only one key in a class may contain a GeoPoint.

      + * + *

      Example:

      + *   var point = new Parse.GeoPoint(30.0, -20.0);
      + *   var object = new Parse.Object("PlaceObject");
      + *   object.set("location", point);
      + *   object.save();

      + */ +var ParseGeoPoint = function () { + function ParseGeoPoint(arg1, arg2) { + (0, _classCallCheck3.default)(this, ParseGeoPoint); + + if (Array.isArray(arg1)) { + ParseGeoPoint._validate(arg1[0], arg1[1]); + this._latitude = arg1[0]; + this._longitude = arg1[1]; + } else if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { + ParseGeoPoint._validate(arg1.latitude, arg1.longitude); + this._latitude = arg1.latitude; + this._longitude = arg1.longitude; + } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { + ParseGeoPoint._validate(arg1, arg2); + this._latitude = arg1; + this._longitude = arg2; + } else { + this._latitude = 0; + this._longitude = 0; + } + } + + /** + * North-south portion of the coordinate, in range [-90, 90]. + * Throws an exception if set out of range in a modern browser. + * @property latitude + * @type Number + */ + + (0, _createClass3.default)(ParseGeoPoint, [{ + key: 'toJSON', + + /** + * Returns a JSON representation of the GeoPoint, suitable for Parse. + * @method toJSON + * @return {Object} + */ + value: function () { + ParseGeoPoint._validate(this._latitude, this._longitude); + return { + __type: 'GeoPoint', + latitude: this._latitude, + longitude: this._longitude + }; + } + }, { + key: 'equals', + value: function (other) { + return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; + } + + /** + * Returns the distance from this GeoPoint to another in radians. + * @method radiansTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'radiansTo', + value: function (point) { + var d2r = Math.PI / 180.0; + var lat1rad = this.latitude * d2r; + var long1rad = this.longitude * d2r; + var lat2rad = point.latitude * d2r; + var long2rad = point.longitude * d2r; + + var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); + var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); + // Square of half the straight line chord distance between both points. + var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; + a = Math.min(1.0, a); + return 2 * Math.asin(Math.sqrt(a)); + } + + /** + * Returns the distance from this GeoPoint to another in kilometers. + * @method kilometersTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'kilometersTo', + value: function (point) { + return this.radiansTo(point) * 6371.0; + } + + /** + * Returns the distance from this GeoPoint to another in miles. + * @method milesTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'milesTo', + value: function (point) { + return this.radiansTo(point) * 3958.8; + } + + /** + * Throws an exception if the given lat-long is out of bounds. + */ + + }, { + key: 'latitude', + get: function () { + return this._latitude; + }, + set: function (val) { + ParseGeoPoint._validate(val, this.longitude); + this._latitude = val; + } + + /** + * East-west portion of the coordinate, in range [-180, 180]. + * Throws if set out of range in a modern browser. + * @property longitude + * @type Number + */ + + }, { + key: 'longitude', + get: function () { + return this._longitude; + }, + set: function (val) { + ParseGeoPoint._validate(this.latitude, val); + this._longitude = val; + } + }], [{ + key: '_validate', + value: function (latitude, longitude) { + if (latitude !== latitude || longitude !== longitude) { + throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); + } + if (latitude < -90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); + } + if (latitude > 90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); + } + if (longitude < -180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); + } + if (longitude > 180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); + } + } + + /** + * Creates a GeoPoint with the user's current location, if available. + * Calls options.success with a new GeoPoint instance or calls options.error. + * @method current + * @param {Object} options An object with success and error callbacks. + * @static + */ + + }, { + key: 'current', + value: function (options) { + var promise = new _ParsePromise2.default(); + navigator.geolocation.getCurrentPosition(function (location) { + promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); + }, function (error) { + promise.reject(error); + }); + + return promise._thenRunCallbacks(options); + } + }]); + return ParseGeoPoint; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseGeoPoint; \ No newline at end of file diff --git a/lib/browser/ParseHooks.js b/lib/browser/ParseHooks.js new file mode 100644 index 000000000..a2057e899 --- /dev/null +++ b/lib/browser/ParseHooks.js @@ -0,0 +1,162 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _promise = require('babel-runtime/core-js/promise'); + +var _promise2 = _interopRequireDefault(_promise); + +exports.getFunctions = getFunctions; +exports.getTriggers = getTriggers; +exports.getFunction = getFunction; +exports.getTrigger = getTrigger; +exports.createFunction = createFunction; +exports.createTrigger = createTrigger; +exports.create = create; +exports.updateFunction = updateFunction; +exports.updateTrigger = updateTrigger; +exports.update = update; +exports.removeFunction = removeFunction; +exports.removeTrigger = removeTrigger; +exports.remove = remove; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function getFunctions() { + return _CoreManager2.default.getHooksController().get("functions"); +} + +function getTriggers() { + return _CoreManager2.default.getHooksController().get("triggers"); +} + +function getFunction(name) { + return _CoreManager2.default.getHooksController().get("functions", name); +} + +function getTrigger(className, triggerName) { + return _CoreManager2.default.getHooksController().get("triggers", className, triggerName); +} + +function createFunction(functionName, url) { + return create({ functionName: functionName, url: url }); +} + +function createTrigger(className, triggerName, url) { + return create({ className: className, triggerName: triggerName, url: url }); +} + +function create(hook) { + return _CoreManager2.default.getHooksController().create(hook); +} + +function updateFunction(functionName, url) { + return update({ functionName: functionName, url: url }); +} + +function updateTrigger(className, triggerName, url) { + return update({ className: className, triggerName: triggerName, url: url }); +} + +function update(hook) { + return _CoreManager2.default.getHooksController().update(hook); +} + +function removeFunction(functionName) { + return remove({ functionName: functionName }); +} + +function removeTrigger(className, triggerName) { + return remove({ className: className, triggerName: triggerName }); +} + +function remove(hook) { + return _CoreManager2.default.getHooksController().remove(hook); +} + +var DefaultController = { + get: function (type, functionName, triggerName) { + var url = "/hooks/" + type; + if (functionName) { + url += "/" + functionName; + if (triggerName) { + url += "/" + triggerName; + } + } + return this.sendRequest("GET", url); + }, + create: function (hook) { + var url; + if (hook.functionName && hook.url) { + url = "/hooks/functions"; + } else if (hook.className && hook.triggerName && hook.url) { + url = "/hooks/triggers"; + } else { + return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest("POST", url, hook); + }, + remove: function (hook) { + var url; + if (hook.functionName) { + url = "/hooks/functions/" + hook.functionName; + delete hook.functionName; + } else if (hook.className && hook.triggerName) { + url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; + delete hook.className; + delete hook.triggerName; + } else { + return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest("PUT", url, { "__op": "Delete" }); + }, + update: function (hook) { + var url; + if (hook.functionName && hook.url) { + url = "/hooks/functions/" + hook.functionName; + delete hook.functionName; + } else if (hook.className && hook.triggerName && hook.url) { + url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; + delete hook.className; + delete hook.triggerName; + } else { + return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest('PUT', url, hook); + }, + sendRequest: function (method, url, body) { + return _CoreManager2.default.getRESTController().request(method, url, body, { useMasterKey: true }).then(function (res) { + var decoded = (0, _decode2.default)(res); + if (decoded) { + return _ParsePromise2.default.as(decoded); + } + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); + }); + } +}; + +_CoreManager2.default.setHooksController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseInstallation.js b/lib/browser/ParseInstallation.js new file mode 100644 index 000000000..02d7be1d8 --- /dev/null +++ b/lib/browser/ParseInstallation.js @@ -0,0 +1,65 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var Installation = function (_ParseObject) { + (0, _inherits3.default)(Installation, _ParseObject); + + function Installation(attributes) { + (0, _classCallCheck3.default)(this, Installation); + + var _this = (0, _possibleConstructorReturn3.default)(this, (Installation.__proto__ || (0, _getPrototypeOf2.default)(Installation)).call(this, '_Installation')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + return _this; + } + + return Installation; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = Installation; + +_ParseObject3.default.registerSubclass('_Installation', Installation); \ No newline at end of file diff --git a/lib/browser/ParseLiveQuery.js b/lib/browser/ParseLiveQuery.js new file mode 100644 index 000000000..a3e5fe31d --- /dev/null +++ b/lib/browser/ParseLiveQuery.js @@ -0,0 +1,241 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _EventEmitter = require('./EventEmitter'); + +var _EventEmitter2 = _interopRequireDefault(_EventEmitter); + +var _LiveQueryClient = require('./LiveQueryClient'); + +var _LiveQueryClient2 = _interopRequireDefault(_LiveQueryClient); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function open() { + var LiveQueryController = _CoreManager2.default.getLiveQueryController(); + LiveQueryController.open(); +} + +function close() { + var LiveQueryController = _CoreManager2.default.getLiveQueryController(); + LiveQueryController.close(); +} + +/** + * + * We expose three events to help you monitor the status of the WebSocket connection: + * + *

      Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

      + * Parse.LiveQuery.on('open', () => {
      + * 
      + * });

      + * + *

      Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

      + * Parse.LiveQuery.on('close', () => {
      + * 
      + * });

      + * + *

      Error - When some network error or LiveQuery server error happens, you'll get this event. + * + *

      + * Parse.LiveQuery.on('error', (error) => {
      + * 
      + * });

      + * + * @class Parse.LiveQuery + * @static + * + */ +var LiveQuery = new _EventEmitter2.default(); + +/** + * After open is called, the LiveQuery will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ +LiveQuery.open = open; + +/** + * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). + * This function will close the WebSocket connection to the LiveQuery server, + * cancel the auto reconnect, and unsubscribe all subscriptions based on it. + * If you call query.subscribe() after this, we'll create a new WebSocket + * connection to the LiveQuery server. + * + * @method close + */ + +LiveQuery.close = close; +// Register a default onError callback to make sure we do not crash on error +LiveQuery.on('error', function () {}); + +exports.default = LiveQuery; + +function getSessionToken() { + var controller = _CoreManager2.default.getUserController(); + return controller.currentUserAsync().then(function (currentUser) { + return currentUser ? currentUser.getSessionToken() : undefined; + }); +} + +function getLiveQueryClient() { + return _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient(); +} + +var defaultLiveQueryClient = void 0; +var DefaultLiveQueryController = { + setDefaultLiveQueryClient: function (liveQueryClient) { + defaultLiveQueryClient = liveQueryClient; + }, + getDefaultLiveQueryClient: function () { + if (defaultLiveQueryClient) { + return _ParsePromise2.default.as(defaultLiveQueryClient); + } + + return getSessionToken().then(function (sessionToken) { + var liveQueryServerURL = _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); + + if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL + if (!liveQueryServerURL) { + var tempServerURL = _CoreManager2.default.get('SERVER_URL'); + var protocol = 'ws://'; + // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix + if (tempServerURL.indexOf('https') === 0) { + protocol = 'wss://'; + } + var host = tempServerURL.replace(/^https?:\/\//, ''); + liveQueryServerURL = protocol + host; + _CoreManager2.default.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); + } + + var applicationId = _CoreManager2.default.get('APPLICATION_ID'); + var javascriptKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); + var masterKey = _CoreManager2.default.get('MASTER_KEY'); + // Get currentUser sessionToken if possible + defaultLiveQueryClient = new _LiveQueryClient2.default({ + applicationId: applicationId, + serverURL: liveQueryServerURL, + javascriptKey: javascriptKey, + masterKey: masterKey, + sessionToken: sessionToken + }); + // Register a default onError callback to make sure we do not crash on error + // Cannot create these events on a nested way because of EventEmiiter from React Native + defaultLiveQueryClient.on('error', function (error) { + LiveQuery.emit('error', error); + }); + defaultLiveQueryClient.on('open', function () { + LiveQuery.emit('open'); + }); + defaultLiveQueryClient.on('close', function () { + LiveQuery.emit('close'); + }); + + return defaultLiveQueryClient; + }); + }, + open: function () { + var _this = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this.resolve(liveQueryClient.open()); + }); + }, + close: function () { + var _this2 = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this2.resolve(liveQueryClient.close()); + }); + }, + subscribe: function (query) { + var _this3 = this; + + var subscriptionWrap = new _EventEmitter2.default(); + + getLiveQueryClient().then(function (liveQueryClient) { + if (liveQueryClient.shouldOpen()) { + liveQueryClient.open(); + } + var promiseSessionToken = getSessionToken(); + // new event emitter + return promiseSessionToken.then(function (sessionToken) { + + var subscription = liveQueryClient.subscribe(query, sessionToken); + // enter, leave create, etc + + subscriptionWrap.id = subscription.id; + subscriptionWrap.query = subscription.query; + subscriptionWrap.sessionToken = subscription.sessionToken; + subscriptionWrap.unsubscribe = subscription.unsubscribe; + // Cannot create these events on a nested way because of EventEmiiter from React Native + subscription.on('open', function () { + subscriptionWrap.emit('open'); + }); + subscription.on('create', function (object) { + subscriptionWrap.emit('create', object); + }); + subscription.on('update', function (object) { + subscriptionWrap.emit('update', object); + }); + subscription.on('enter', function (object) { + subscriptionWrap.emit('enter', object); + }); + subscription.on('leave', function (object) { + subscriptionWrap.emit('leave', object); + }); + subscription.on('delete', function (object) { + subscriptionWrap.emit('delete', object); + }); + + _this3.resolve(); + }); + }); + return subscriptionWrap; + }, + unsubscribe: function (subscription) { + var _this4 = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this4.resolve(liveQueryClient.unsubscribe(subscription)); + }); + }, + _clearCachedDefaultClient: function () { + defaultLiveQueryClient = null; + } +}; + +_CoreManager2.default.setLiveQueryController(DefaultLiveQueryController); \ No newline at end of file diff --git a/lib/browser/ParseObject.js b/lib/browser/ParseObject.js new file mode 100644 index 000000000..f08795e52 --- /dev/null +++ b/lib/browser/ParseObject.js @@ -0,0 +1,2001 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _defineProperty = require('babel-runtime/core-js/object/define-property'); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +var _create = require('babel-runtime/core-js/object/create'); + +var _create2 = _interopRequireDefault(_create); + +var _freeze = require('babel-runtime/core-js/object/freeze'); + +var _freeze2 = _interopRequireDefault(_freeze); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _canBeSerialized = require('./canBeSerialized'); + +var _canBeSerialized2 = _interopRequireDefault(_canBeSerialized); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _equals = require('./equals'); + +var _equals2 = _interopRequireDefault(_equals); + +var _escape2 = require('./escape'); + +var _escape3 = _interopRequireDefault(_escape2); + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _parseDate = require('./parseDate'); + +var _parseDate2 = _interopRequireDefault(_parseDate); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseOp = require('./ParseOp'); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseQuery = require('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _SingleInstanceStateController = require('./SingleInstanceStateController'); + +var SingleInstanceStateController = _interopRequireWildcard(_SingleInstanceStateController); + +var _unique = require('./unique'); + +var _unique2 = _interopRequireDefault(_unique); + +var _UniqueInstanceStateController = require('./UniqueInstanceStateController'); + +var UniqueInstanceStateController = _interopRequireWildcard(_UniqueInstanceStateController); + +var _unsavedChildren = require('./unsavedChildren'); + +var _unsavedChildren2 = _interopRequireDefault(_unsavedChildren); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +// Mapping of class names to constructors, so we can populate objects from the +// server with appropriate subclasses of ParseObject +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var classMap = {}; + +// Global counter for generating unique local Ids +var localCount = 0; +// Global counter for generating unique Ids for non-single-instance objects +var objectCount = 0; +// On web clients, objects are single-instance: any two objects with the same Id +// will have the same attributes. However, this may be dangerous default +// behavior in a server scenario +var singleInstance = !_CoreManager2.default.get('IS_NODE'); +if (singleInstance) { + _CoreManager2.default.setObjectStateController(SingleInstanceStateController); +} else { + _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); +} + +function getServerUrlPath() { + var serverUrl = _CoreManager2.default.get('SERVER_URL'); + if (serverUrl[serverUrl.length - 1] !== '/') { + serverUrl += '/'; + } + var url = serverUrl.replace(/https?:\/\//, ''); + return url.substr(url.indexOf('/')); +} + +/** + * Creates a new model with defined attributes. + * + *

      You won't normally call this method directly. It is recommended that + * you use a subclass of Parse.Object instead, created by calling + * extend.

      + * + *

      However, if you don't want to use a subclass, or aren't sure which + * subclass is appropriate, you can use this form:

      + *     var object = new Parse.Object("ClassName");
      + * 
      + * That is basically equivalent to:
      + *     var MyClass = Parse.Object.extend("ClassName");
      + *     var object = new MyClass();
      + * 

      + * + * @class Parse.Object + * @constructor + * @param {String} className The class name for the object + * @param {Object} attributes The initial set of data to store in the object. + * @param {Object} options The options for this object instance. + */ + +var ParseObject = function () { + /** + * The ID of this object, unique within its class. + * @property id + * @type String + */ + function ParseObject(className, attributes, options) { + (0, _classCallCheck3.default)(this, ParseObject); + + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + var toSet = null; + this._objCount = objectCount++; + if (typeof className === 'string') { + this.className = className; + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + toSet = attributes; + } + } else if (className && (typeof className === 'undefined' ? 'undefined' : (0, _typeof3.default)(className)) === 'object') { + this.className = className.className; + toSet = {}; + for (var attr in className) { + if (attr !== 'className') { + toSet[attr] = className[attr]; + } + } + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + options = attributes; + } + } + if (toSet && !this.set(toSet, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + + /** Prototype getters / setters **/ + + (0, _createClass3.default)(ParseObject, [{ + key: '_getId', + + /** Private methods **/ + + /** + * Returns a local or server Id used uniquely identify this object + */ + value: function () { + if (typeof this.id === 'string') { + return this.id; + } + if (typeof this._localId === 'string') { + return this._localId; + } + var localId = 'local' + String(localCount++); + this._localId = localId; + return localId; + } + + /** + * Returns a unique identifier used to pull data from the State Controller. + */ + + }, { + key: '_getStateIdentifier', + value: function () { + if (singleInstance) { + var _id = this.id; + if (!_id) { + _id = this._getId(); + } + return { + id: _id, + className: this.className + }; + } else { + return this; + } + } + }, { + key: '_getServerData', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return stateController.getServerData(this._getStateIdentifier()); + } + }, { + key: '_clearServerData', + value: function () { + var serverData = this._getServerData(); + var unset = {}; + for (var attr in serverData) { + unset[attr] = undefined; + } + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.setServerData(this._getStateIdentifier(), unset); + } + }, { + key: '_getPendingOps', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return stateController.getPendingOps(this._getStateIdentifier()); + } + }, { + key: '_clearPendingOps', + value: function () { + var pending = this._getPendingOps(); + var latest = pending[pending.length - 1]; + var keys = (0, _keys2.default)(latest); + keys.forEach(function (key) { + delete latest[key]; + }); + } + }, { + key: '_getDirtyObjectAttributes', + value: function () { + var attributes = this.attributes; + var stateController = _CoreManager2.default.getObjectStateController(); + var objectCache = stateController.getObjectCache(this._getStateIdentifier()); + var dirty = {}; + for (var attr in attributes) { + var val = attributes[attr]; + if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof ParseObject) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { + // Due to the way browsers construct maps, the key order will not change + // unless the object is changed + try { + var json = (0, _encode2.default)(val, false, true); + var stringified = (0, _stringify2.default)(json); + if (objectCache[attr] !== stringified) { + dirty[attr] = val; + } + } catch (e) { + // Error occurred, possibly by a nested unsaved pointer in a mutable container + // No matter how it happened, it indicates a change in the attribute + dirty[attr] = val; + } + } + } + return dirty; + } + }, { + key: '_toFullJSON', + value: function (seen) { + var json = this.toJSON(seen); + json.__type = 'Object'; + json.className = this.className; + return json; + } + }, { + key: '_getSaveJSON', + value: function () { + var pending = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + var json = {}; + + for (var attr in dirtyObjects) { + json[attr] = new _ParseOp.SetOp(dirtyObjects[attr]).toJSON(); + } + for (attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + return json; + } + }, { + key: '_getSaveParams', + value: function () { + var method = this.id ? 'PUT' : 'POST'; + var body = this._getSaveJSON(); + var path = 'classes/' + this.className; + if (this.id) { + path += '/' + this.id; + } else if (this.className === '_User') { + path = 'users'; + } + return { + method: method, + body: body, + path: path + }; + } + }, { + key: '_finishFetch', + value: function (serverData) { + if (!this.id && serverData.objectId) { + this.id = serverData.objectId; + } + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.initializeState(this._getStateIdentifier()); + var decoded = {}; + for (var attr in serverData) { + if (attr === 'ACL') { + decoded[attr] = new _ParseACL2.default(serverData[attr]); + } else if (attr !== 'objectId') { + decoded[attr] = (0, _decode2.default)(serverData[attr]); + if (decoded[attr] instanceof _ParseRelation2.default) { + decoded[attr]._ensureParentAndKey(this, attr); + } + } + } + if (decoded.createdAt && typeof decoded.createdAt === 'string') { + decoded.createdAt = (0, _parseDate2.default)(decoded.createdAt); + } + if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { + decoded.updatedAt = (0, _parseDate2.default)(decoded.updatedAt); + } + if (!decoded.updatedAt && decoded.createdAt) { + decoded.updatedAt = decoded.createdAt; + } + stateController.commitServerChanges(this._getStateIdentifier(), decoded); + } + }, { + key: '_setExisted', + value: function (existed) { + var stateController = _CoreManager2.default.getObjectStateController(); + var state = stateController.getState(this._getStateIdentifier()); + if (state) { + state.existed = existed; + } + } + }, { + key: '_migrateId', + value: function (serverId) { + if (this._localId && serverId) { + if (singleInstance) { + var stateController = _CoreManager2.default.getObjectStateController(); + var oldState = stateController.removeState(this._getStateIdentifier()); + this.id = serverId; + delete this._localId; + if (oldState) { + stateController.initializeState(this._getStateIdentifier(), oldState); + } + } else { + this.id = serverId; + delete this._localId; + } + } + } + }, { + key: '_handleSaveResponse', + value: function (response, status) { + var changes = {}; + + var stateController = _CoreManager2.default.getObjectStateController(); + var pending = stateController.popPendingState(this._getStateIdentifier()); + for (var attr in pending) { + if (pending[attr] instanceof _ParseOp.RelationOp) { + changes[attr] = pending[attr].applyTo(undefined, this, attr); + } else if (!(attr in response)) { + // Only SetOps and UnsetOps should not come back with results + changes[attr] = pending[attr].applyTo(undefined); + } + } + for (attr in response) { + if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { + changes[attr] = (0, _parseDate2.default)(response[attr]); + } else if (attr === 'ACL') { + changes[attr] = new _ParseACL2.default(response[attr]); + } else if (attr !== 'objectId') { + changes[attr] = (0, _decode2.default)(response[attr]); + if (changes[attr] instanceof _ParseOp.UnsetOp) { + changes[attr] = undefined; + } + } + } + if (changes.createdAt && !changes.updatedAt) { + changes.updatedAt = changes.createdAt; + } + + this._migrateId(response.objectId); + + if (status !== 201) { + this._setExisted(true); + } + + stateController.commitServerChanges(this._getStateIdentifier(), changes); + } + }, { + key: '_handleSaveError', + value: function () { + this._getPendingOps(); + + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.mergeFirstPendingState(this._getStateIdentifier()); + } + + /** Public methods **/ + + }, { + key: 'initialize', + value: function () {} + // NOOP + + + /** + * Returns a JSON version of the object suitable for saving to Parse. + * @method toJSON + * @return {Object} + */ + + }, { + key: 'toJSON', + value: function (seen) { + var seenEntry = this.id ? this.className + ':' + this.id : this; + var seen = seen || [seenEntry]; + var json = {}; + var attrs = this.attributes; + for (var attr in attrs) { + if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { + json[attr] = attrs[attr].toJSON(); + } else { + json[attr] = (0, _encode2.default)(attrs[attr], false, false, seen); + } + } + var pending = this._getPendingOps(); + for (var attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + + if (this.id) { + json.objectId = this.id; + } + return json; + } + + /** + * Determines whether this ParseObject is equal to another ParseObject + * @method equals + * @return {Boolean} + */ + + }, { + key: 'equals', + value: function (other) { + if (this === other) { + return true; + } + return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; + } + + /** + * Returns true if this object has been modified since its last + * save/refresh. If an attribute is specified, it returns true only if that + * particular attribute has been modified since the last save/refresh. + * @method dirty + * @param {String} attr An attribute name (optional). + * @return {Boolean} + */ + + }, { + key: 'dirty', + value: function (attr) { + if (!this.id) { + return true; + } + var pendingOps = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + if (attr) { + if (dirtyObjects.hasOwnProperty(attr)) { + return true; + } + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i].hasOwnProperty(attr)) { + return true; + } + } + return false; + } + if ((0, _keys2.default)(pendingOps[0]).length !== 0) { + return true; + } + if ((0, _keys2.default)(dirtyObjects).length !== 0) { + return true; + } + return false; + } + + /** + * Returns an array of keys that have been modified since last save/refresh + * @method dirtyKeys + * @return {Array of string} + */ + + }, { + key: 'dirtyKeys', + value: function () { + var pendingOps = this._getPendingOps(); + var keys = {}; + for (var i = 0; i < pendingOps.length; i++) { + for (var attr in pendingOps[i]) { + keys[attr] = true; + } + } + var dirtyObjects = this._getDirtyObjectAttributes(); + for (var attr in dirtyObjects) { + keys[attr] = true; + } + return (0, _keys2.default)(keys); + } + + /** + * Gets a Pointer referencing this Object. + * @method toPointer + * @return {Object} + */ + + }, { + key: 'toPointer', + value: function () { + if (!this.id) { + throw new Error('Cannot create a pointer to an unsaved ParseObject'); + } + return { + __type: 'Pointer', + className: this.className, + objectId: this.id + }; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'get', + value: function (attr) { + return this.attributes[attr]; + } + + /** + * Gets a relation on the given class for the attribute. + * @method relation + * @param String attr The attribute to get the relation for. + */ + + }, { + key: 'relation', + value: function (attr) { + var value = this.get(attr); + if (value) { + if (!(value instanceof _ParseRelation2.default)) { + throw new Error('Called relation() on non-relation field ' + attr); + } + value._ensureParentAndKey(this, attr); + return value; + } + return new _ParseRelation2.default(this, attr); + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'escape', + value: function (attr) { + var val = this.attributes[attr]; + if (val == null) { + return ''; + } + + if (typeof val !== 'string') { + if (typeof val.toString !== 'function') { + return ''; + } + val = val.toString(); + } + return (0, _escape3.default)(val); + } + + /** + * Returns true if the attribute contains a value that is not + * null or undefined. + * @method has + * @param {String} attr The string name of the attribute. + * @return {Boolean} + */ + + }, { + key: 'has', + value: function (attr) { + var attributes = this.attributes; + if (attributes.hasOwnProperty(attr)) { + return attributes[attr] != null; + } + return false; + } + + /** + * Sets a hash of model attributes on the object. + * + *

      You can call it with an object containing keys and values, or with one + * key and value. For example:

      +     *   gameTurn.set({
      +     *     player: player1,
      +     *     diceRoll: 2
      +     *   }, {
      +     *     error: function(gameTurnAgain, error) {
      +     *       // The set failed validation.
      +     *     }
      +     *   });
      +     *
      +     *   game.set("currentPlayer", player2, {
      +     *     error: function(gameTurnAgain, error) {
      +     *       // The set failed validation.
      +     *     }
      +     *   });
      +     *
      +     *   game.set("finished", true);

      + * + * @method set + * @param {String} key The key to set. + * @param {} value The value to give it. + * @param {Object} options A set of options for the set. + * The only supported option is error. + * @return {Boolean} true if the set succeeded. + */ + + }, { + key: 'set', + value: function (key, value, options) { + var changes = {}; + var newOps = {}; + if (key && (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'object') { + changes = key; + options = value; + } else if (typeof key === 'string') { + changes[key] = value; + } else { + return this; + } + + options = options || {}; + var readonly = []; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var k in changes) { + if (k === 'createdAt' || k === 'updatedAt') { + // This property is read-only, but for legacy reasons we silently + // ignore it + continue; + } + if (readonly.indexOf(k) > -1) { + throw new Error('Cannot modify readonly attribute: ' + k); + } + if (options.unset) { + newOps[k] = new _ParseOp.UnsetOp(); + } else if (changes[k] instanceof _ParseOp.Op) { + newOps[k] = changes[k]; + } else if (changes[k] && (0, _typeof3.default)(changes[k]) === 'object' && typeof changes[k].__op === 'string') { + newOps[k] = (0, _ParseOp.opFromJSON)(changes[k]); + } else if (k === 'objectId' || k === 'id') { + if (typeof changes[k] === 'string') { + this.id = changes[k]; + } + } else if (k === 'ACL' && (0, _typeof3.default)(changes[k]) === 'object' && !(changes[k] instanceof _ParseACL2.default)) { + newOps[k] = new _ParseOp.SetOp(new _ParseACL2.default(changes[k])); + } else { + newOps[k] = new _ParseOp.SetOp(changes[k]); + } + } + + // Calculate new values + var currentAttributes = this.attributes; + var newValues = {}; + for (var attr in newOps) { + if (newOps[attr] instanceof _ParseOp.RelationOp) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); + } else if (!(newOps[attr] instanceof _ParseOp.UnsetOp)) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); + } + } + + // Validate changes + if (!options.ignoreValidation) { + var validation = this.validate(newValues); + if (validation) { + if (typeof options.error === 'function') { + options.error(this, validation); + } + return false; + } + } + + // Consolidate Ops + var pendingOps = this._getPendingOps(); + var last = pendingOps.length - 1; + var stateController = _CoreManager2.default.getObjectStateController(); + for (var attr in newOps) { + var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); + stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); + } + + return this; + } + + /** + * Remove an attribute from the model. This is a noop if the attribute doesn't + * exist. + * @method unset + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'unset', + value: function (attr, options) { + options = options || {}; + options.unset = true; + return this.set(attr, null, options); + } + + /** + * Atomically increments the value of the given attribute the next time the + * object is saved. If no amount is specified, 1 is used by default. + * + * @method increment + * @param attr {String} The key. + * @param amount {Number} The amount to increment by (optional). + */ + + }, { + key: 'increment', + value: function (attr, amount) { + if (typeof amount === 'undefined') { + amount = 1; + } + if (typeof amount !== 'number') { + throw new Error('Cannot increment by a non-numeric amount.'); + } + return this.set(attr, new _ParseOp.IncrementOp(amount)); + } + + /** + * Atomically add an object to the end of the array associated with a given + * key. + * @method add + * @param attr {String} The key. + * @param item {} The item to add. + */ + + }, { + key: 'add', + value: function (attr, item) { + return this.set(attr, new _ParseOp.AddOp([item])); + } + + /** + * Atomically add an object to the array associated with a given key, only + * if it is not already present in the array. The position of the insert is + * not guaranteed. + * + * @method addUnique + * @param attr {String} The key. + * @param item {} The object to add. + */ + + }, { + key: 'addUnique', + value: function (attr, item) { + return this.set(attr, new _ParseOp.AddUniqueOp([item])); + } + + /** + * Atomically remove all instances of an object from the array associated + * with a given key. + * + * @method remove + * @param attr {String} The key. + * @param item {} The object to remove. + */ + + }, { + key: 'remove', + value: function (attr, item) { + return this.set(attr, new _ParseOp.RemoveOp([item])); + } + + /** + * Returns an instance of a subclass of Parse.Op describing what kind of + * modification has been performed on this field since the last time it was + * saved. For example, after calling object.increment("x"), calling + * object.op("x") would return an instance of Parse.Op.Increment. + * + * @method op + * @param attr {String} The key. + * @returns {Parse.Op} The operation, or undefined if none. + */ + + }, { + key: 'op', + value: function (attr) { + var pending = this._getPendingOps(); + for (var i = pending.length; i--;) { + if (pending[i][attr]) { + return pending[i][attr]; + } + } + } + + /** + * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() + * @method clone + * @return {Parse.Object} + */ + + }, { + key: 'clone', + value: function () { + var clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + var attributes = this.attributes; + if (typeof this.constructor.readOnlyAttributes === 'function') { + var readonly = this.constructor.readOnlyAttributes() || []; + // Attributes are frozen, so we have to rebuild an object, + // rather than delete readonly keys + var copy = {}; + for (var a in attributes) { + if (readonly.indexOf(a) < 0) { + copy[a] = attributes[a]; + } + } + attributes = copy; + } + if (clone.set) { + clone.set(attributes); + } + return clone; + } + + /** + * Creates a new instance of this object. Not to be confused with clone() + * @method newInstance + * @return {Parse.Object} + */ + + }, { + key: 'newInstance', + value: function () { + var clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + clone.id = this.id; + if (singleInstance) { + // Just return an object with the right id + return clone; + } + + var stateController = _CoreManager2.default.getObjectStateController(); + if (stateController) { + stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); + } + return clone; + } + + /** + * Returns true if this object has never been saved to Parse. + * @method isNew + * @return {Boolean} + */ + + }, { + key: 'isNew', + value: function () { + return !this.id; + } + + /** + * Returns true if this object was created by the Parse server when the + * object might have already been there (e.g. in the case of a Facebook + * login) + * @method existed + * @return {Boolean} + */ + + }, { + key: 'existed', + value: function () { + if (!this.id) { + return false; + } + var stateController = _CoreManager2.default.getObjectStateController(); + var state = stateController.getState(this._getStateIdentifier()); + if (state) { + return state.existed; + } + return false; + } + + /** + * Checks if the model is currently in a valid state. + * @method isValid + * @return {Boolean} + */ + + }, { + key: 'isValid', + value: function () { + return !this.validate(this.attributes); + } + + /** + * You should not call this function directly unless you subclass + * Parse.Object, in which case you can override this method + * to provide additional validation on set and + * save. Your implementation should return + * + * @method validate + * @param {Object} attrs The current data to validate. + * @return {} False if the data is valid. An error object otherwise. + * @see Parse.Object#set + */ + + }, { + key: 'validate', + value: function (attrs) { + if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof _ParseACL2.default)) { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'ACL must be a Parse ACL.'); + } + for (var key in attrs) { + if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { + return new _ParseError2.default(_ParseError2.default.INVALID_KEY_NAME); + } + } + return false; + } + + /** + * Returns the ACL for this object. + * @method getACL + * @returns {Parse.ACL} An instance of Parse.ACL. + * @see Parse.Object#get + */ + + }, { + key: 'getACL', + value: function () { + var acl = this.get('ACL'); + if (acl instanceof _ParseACL2.default) { + return acl; + } + return null; + } + + /** + * Sets the ACL to be used for this object. + * @method setACL + * @param {Parse.ACL} acl An instance of Parse.ACL. + * @param {Object} options Optional Backbone-like options object to be + * passed in to set. + * @return {Boolean} Whether the set passed validation. + * @see Parse.Object#set + */ + + }, { + key: 'setACL', + value: function (acl, options) { + return this.set('ACL', acl, options); + } + + /** + * Clears any changes to this object made since the last call to save() + * @method revert + */ + + }, { + key: 'revert', + value: function () { + this._clearPendingOps(); + } + + /** + * Clears all attributes on a model + * @method clear + */ + + }, { + key: 'clear', + value: function () { + var attributes = this.attributes; + var erasable = {}; + var readonly = ['createdAt', 'updatedAt']; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var attr in attributes) { + if (readonly.indexOf(attr) < 0) { + erasable[attr] = true; + } + } + return this.set(erasable, { unset: true }); + } + + /** + * Fetch the model from the server. If the server's representation of the + * model differs from its current attributes, they will be overriden. + * + * @method fetch + * @param {Object} options A Backbone-style callback object. + * Valid options are:
        + *
      • success: A Backbone-style success callback. + *
      • error: An Backbone-style error callback. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * @return {Parse.Promise} A promise that is fulfilled when the fetch + * completes. + */ + + }, { + key: 'fetch', + value: function (options) { + options = options || {}; + var fetchOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + fetchOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + fetchOptions.sessionToken = options.sessionToken; + } + var controller = _CoreManager2.default.getObjectController(); + return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); + } + + /** + * Set a hash of model attributes, and save the model to the server. + * updatedAt will be updated when the request returns. + * You can either call it as:
      +     *   object.save();
      + * or
      +     *   object.save(null, options);
      + * or
      +     *   object.save(attrs, options);
      + * or
      +     *   object.save(key, value, options);
      + * + * For example,
      +     *   gameTurn.save({
      +     *     player: "Jake Cutter",
      +     *     diceRoll: 2
      +     *   }, {
      +     *     success: function(gameTurnAgain) {
      +     *       // The save was successful.
      +     *     },
      +     *     error: function(gameTurnAgain, error) {
      +     *       // The save failed.  Error is an instance of Parse.Error.
      +     *     }
      +     *   });
      + * or with promises:
      +     *   gameTurn.save({
      +     *     player: "Jake Cutter",
      +     *     diceRoll: 2
      +     *   }).then(function(gameTurnAgain) {
      +     *     // The save was successful.
      +     *   }, function(error) {
      +     *     // The save failed.  Error is an instance of Parse.Error.
      +     *   });
      + * + * @method save + * @param {Object} options A Backbone-style callback object. + * Valid options are:
        + *
      • success: A Backbone-style success callback. + *
      • error: An Backbone-style error callback. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * @return {Parse.Promise} A promise that is fulfilled when the save + * completes. + */ + + }, { + key: 'save', + value: function (arg1, arg2, arg3) { + var _this = this; + + var attrs; + var options; + if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object' || typeof arg1 === 'undefined') { + attrs = arg1; + if ((typeof arg2 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg2)) === 'object') { + options = arg2; + } + } else { + attrs = {}; + attrs[arg1] = arg2; + options = arg3; + } + + // Support save({ success: function() {}, error: function() {} }) + if (!options && attrs) { + options = {}; + if (typeof attrs.success === 'function') { + options.success = attrs.success; + delete attrs.success; + } + if (typeof attrs.error === 'function') { + options.error = attrs.error; + delete attrs.error; + } + } + + if (attrs) { + var validation = this.validate(attrs); + if (validation) { + if (options && typeof options.error === 'function') { + options.error(this, validation); + } + return _ParsePromise2.default.error(validation); + } + this.set(attrs, options); + } + + options = options || {}; + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = !!options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { + saveOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getObjectController(); + var unsaved = (0, _unsavedChildren2.default)(this); + return controller.save(unsaved, saveOptions).then(function () { + return controller.save(_this, saveOptions); + })._thenRunCallbacks(options, this); + } + + /** + * Destroy this model on the server if it was already persisted. + * If `wait: true` is passed, waits for the server to respond + * before removal. + * + * @method destroy + * @param {Object} options A Backbone-style callback object. + * Valid options are:
        + *
      • success: A Backbone-style success callback + *
      • error: An Backbone-style error callback. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * @return {Parse.Promise} A promise that is fulfilled when the destroy + * completes. + */ + + }, { + key: 'destroy', + value: function (options) { + options = options || {}; + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + if (!this.id) { + return _ParsePromise2.default.as()._thenRunCallbacks(options); + } + return _CoreManager2.default.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); + } + + /** Static methods **/ + + }, { + key: 'attributes', + get: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return (0, _freeze2.default)(stateController.estimateAttributes(this._getStateIdentifier())); + } + + /** + * The first time this object was saved on the server. + * @property createdAt + * @type Date + */ + + }, { + key: 'createdAt', + get: function () { + return this._getServerData().createdAt; + } + + /** + * The last time this object was updated on the server. + * @property updatedAt + * @type Date + */ + + }, { + key: 'updatedAt', + get: function () { + return this._getServerData().updatedAt; + } + }], [{ + key: '_clearAllState', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.clearAllState(); + } + + /** + * Fetches the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
      +     *   Parse.Object.fetchAll([object1, object2, ...], {
      +     *     success: function(list) {
      +     *       // All the objects were fetched.
      +     *     },
      +     *     error: function(error) {
      +     *       // An error occurred while fetching one of the objects.
      +     *     },
      +     *   });
      +     * 
      + * + * @method fetchAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
        + *
      • success: A Backbone-style success callback. + *
      • error: An Backbone-style error callback. + *
      + */ + + }, { + key: 'fetchAll', + value: function (list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); + } + + /** + * Fetches the given list of Parse.Object if needed. + * If any error is encountered, stops and calls the error handler. + * + *
      +     *   Parse.Object.fetchAllIfNeeded([object1, ...], {
      +     *     success: function(list) {
      +     *       // Objects were fetched and updated.
      +     *     },
      +     *     error: function(error) {
      +     *       // An error occurred while fetching one of the objects.
      +     *     },
      +     *   });
      +     * 
      + * + * @method fetchAllIfNeeded + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
        + *
      • success: A Backbone-style success callback. + *
      • error: An Backbone-style error callback. + *
      + */ + + }, { + key: 'fetchAllIfNeeded', + value: function (list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); + } + + /** + * Destroy the given list of models on the server if it was already persisted. + * + *

      Unlike saveAll, if an error occurs while deleting an individual model, + * this method will continue trying to delete the rest of the models if + * possible, except in the case of a fatal error like a connection error. + * + *

      In particular, the Parse.Error object returned in the case of error may + * be one of two types: + * + *

        + *
      • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an + * array of other Parse.Error objects. Each error object in this array + * has an "object" property that references the object that could not be + * deleted (for instance, because that object could not be found).
      • + *
      • A non-aggregate Parse.Error. This indicates a serious error that + * caused the delete operation to be aborted partway through (for + * instance, a connection failure in the middle of the delete).
      • + *
      + * + *
      +     *   Parse.Object.destroyAll([object1, object2, ...], {
      +     *     success: function() {
      +     *       // All the objects were deleted.
      +     *     },
      +     *     error: function(error) {
      +     *       // An error occurred while deleting one or more of the objects.
      +     *       // If this is an aggregate error, then we can inspect each error
      +     *       // object individually to determine the reason why a particular
      +     *       // object was not deleted.
      +     *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
      +     *         for (var i = 0; i < error.errors.length; i++) {
      +     *           console.log("Couldn't delete " + error.errors[i].object.id +
      +     *             "due to " + error.errors[i].message);
      +     *         }
      +     *       } else {
      +     *         console.log("Delete aborted because of " + error.message);
      +     *       }
      +     *     },
      +     *   });
      +     * 
      + * + * @method destroyAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
        + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * @return {Parse.Promise} A promise that is fulfilled when the destroyAll + * completes. + */ + + }, { + key: 'destroyAll', + value: function (list, options) { + var options = options || {}; + + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); + } + + /** + * Saves the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
      +     *   Parse.Object.saveAll([object1, object2, ...], {
      +     *     success: function(list) {
      +     *       // All the objects were saved.
      +     *     },
      +     *     error: function(error) {
      +     *       // An error occurred while saving one of the objects.
      +     *     },
      +     *   });
      +     * 
      + * + * @method saveAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
        + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + */ + + }, { + key: 'saveAll', + value: function (list, options) { + var options = options || {}; + + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + saveOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); + } + + /** + * Creates a reference to a subclass of Parse.Object with the given id. This + * does not exist on Parse.Object, only on subclasses. + * + *

      A shortcut for:

      +     *  var Foo = Parse.Object.extend("Foo");
      +     *  var pointerToFoo = new Foo();
      +     *  pointerToFoo.id = "myObjectId";
      +     * 
      + * + * @method createWithoutData + * @param {String} id The ID of the object to create a reference to. + * @static + * @return {Parse.Object} A Parse.Object reference. + */ + + }, { + key: 'createWithoutData', + value: function (id) { + var obj = new this(); + obj.id = id; + return obj; + } + + /** + * Creates a new instance of a Parse Object from a JSON representation. + * @method fromJSON + * @param {Object} json The JSON map of the Object's data + * @param {boolean} override In single instance mode, all old server data + * is overwritten if this is set to true + * @static + * @return {Parse.Object} A Parse.Object reference + */ + + }, { + key: 'fromJSON', + value: function (json, override) { + if (!json.className) { + throw new Error('Cannot create an object without a className'); + } + var constructor = classMap[json.className]; + var o = constructor ? new constructor() : new ParseObject(json.className); + var otherAttributes = {}; + for (var attr in json) { + if (attr !== 'className' && attr !== '__type') { + otherAttributes[attr] = json[attr]; + } + } + if (override) { + // id needs to be set before clearServerData can work + if (otherAttributes.objectId) { + o.id = otherAttributes.objectId; + } + var preserved = null; + if (typeof o._preserveFieldsOnFetch === 'function') { + preserved = o._preserveFieldsOnFetch(); + } + o._clearServerData(); + if (preserved) { + o._finishFetch(preserved); + } + } + o._finishFetch(otherAttributes); + if (json.objectId) { + o._setExisted(true); + } + return o; + } + + /** + * Registers a subclass of Parse.Object with a specific class name. + * When objects of that class are retrieved from a query, they will be + * instantiated with this subclass. + * This is only necessary when using ES6 subclassing. + * @method registerSubclass + * @param {String} className The class name of the subclass + * @param {Class} constructor The subclass + */ + + }, { + key: 'registerSubclass', + value: function (className, constructor) { + if (typeof className !== 'string') { + throw new TypeError('The first argument must be a valid class name.'); + } + if (typeof constructor === 'undefined') { + throw new TypeError('You must supply a subclass constructor.'); + } + if (typeof constructor !== 'function') { + throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); + } + classMap[className] = constructor; + if (!constructor.className) { + constructor.className = className; + } + } + + /** + * Creates a new subclass of Parse.Object for the given Parse class name. + * + *

      Every extension of a Parse class will inherit from the most recent + * previous extension of that class. When a Parse.Object is automatically + * created by parsing JSON, it will use the most recent extension of that + * class.

      + * + *

      You should call either:

      +     *     var MyClass = Parse.Object.extend("MyClass", {
      +     *         Instance methods,
      +     *         initialize: function(attrs, options) {
      +     *             this.someInstanceProperty = [],
      +     *             Other instance properties
      +     *         }
      +     *     }, {
      +     *         Class properties
      +     *     });
      + * or, for Backbone compatibility:
      +     *     var MyClass = Parse.Object.extend({
      +     *         className: "MyClass",
      +     *         Instance methods,
      +     *         initialize: function(attrs, options) {
      +     *             this.someInstanceProperty = [],
      +     *             Other instance properties
      +     *         }
      +     *     }, {
      +     *         Class properties
      +     *     });

      + * + * @method extend + * @param {String} className The name of the Parse class backing this model. + * @param {Object} protoProps Instance properties to add to instances of the + * class returned from this method. + * @param {Object} classProps Class properties to add the class returned from + * this method. + * @return {Class} A new subclass of Parse.Object. + */ + + }, { + key: 'extend', + value: function (className, protoProps, classProps) { + if (typeof className !== 'string') { + if (className && typeof className.className === 'string') { + return ParseObject.extend(className.className, className, protoProps); + } else { + throw new Error('Parse.Object.extend\'s first argument should be the className.'); + } + } + var adjustedClassName = className; + + if (adjustedClassName === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { + adjustedClassName = '_User'; + } + + var parentProto = ParseObject.prototype; + if (this.hasOwnProperty('__super__') && this.__super__) { + parentProto = this.prototype; + } else if (classMap[adjustedClassName]) { + parentProto = classMap[adjustedClassName].prototype; + } + var ParseObjectSubclass = function (attributes, options) { + this.className = adjustedClassName; + this._objCount = objectCount++; + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!this.set(attributes || {}, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + }; + ParseObjectSubclass.className = adjustedClassName; + ParseObjectSubclass.__super__ = parentProto; + + ParseObjectSubclass.prototype = (0, _create2.default)(parentProto, { + constructor: { + value: ParseObjectSubclass, + enumerable: false, + writable: true, + configurable: true + } + }); + + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseObjectSubclass.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseObjectSubclass, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + ParseObjectSubclass.extend = function (name, protoProps, classProps) { + if (typeof name === 'string') { + return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); + } + return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); + }; + ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; + + classMap[adjustedClassName] = ParseObjectSubclass; + return ParseObjectSubclass; + } + + /** + * Enable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * This is disabled by default in server environments, since it can lead to + * security issues. + * @method enableSingleInstance + */ + + }, { + key: 'enableSingleInstance', + value: function () { + singleInstance = true; + _CoreManager2.default.setObjectStateController(SingleInstanceStateController); + } + + /** + * Disable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * When disabled, you can have two instances of the same object in memory + * without them sharing attributes. + * @method disableSingleInstance + */ + + }, { + key: 'disableSingleInstance', + value: function () { + singleInstance = false; + _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); + } + }]); + return ParseObject; +}(); + +exports.default = ParseObject; + +var DefaultController = { + fetch: function (target, forceFetch, options) { + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + var objs = []; + var ids = []; + var className = null; + var results = []; + var error = null; + target.forEach(function (el, i) { + if (error) { + return; + } + if (!className) { + className = el.className; + } + if (className !== el.className) { + error = new _ParseError2.default(_ParseError2.default.INVALID_CLASS_NAME, 'All objects should be of the same class'); + } + if (!el.id) { + error = new _ParseError2.default(_ParseError2.default.MISSING_OBJECT_ID, 'All objects must have an ID'); + } + if (forceFetch || (0, _keys2.default)(el._getServerData()).length === 0) { + ids.push(el.id); + objs.push(el); + } + results.push(el); + }); + if (error) { + return _ParsePromise2.default.error(error); + } + var query = new _ParseQuery2.default(className); + query.containedIn('objectId', ids); + query._limit = ids.length; + return query.find(options).then(function (objects) { + var idMap = {}; + objects.forEach(function (o) { + idMap[o.id] = o; + }); + for (var i = 0; i < objs.length; i++) { + var obj = objs[i]; + if (!obj || !obj.id || !idMap[obj.id]) { + if (forceFetch) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); + } + } + } + if (!singleInstance) { + // If single instance objects are disabled, we need to replace the + for (var i = 0; i < results.length; i++) { + var obj = results[i]; + if (obj && obj.id && idMap[obj.id]) { + var id = obj.id; + obj._finishFetch(idMap[id].toJSON()); + results[i] = idMap[id]; + } + } + } + return _ParsePromise2.default.as(results); + }); + } else { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function (response, status, xhr) { + if (target instanceof ParseObject) { + target._clearPendingOps(); + target._clearServerData(); + target._finishFetch(response); + } + return target; + }); + } + }, + destroy: function (target, options) { + var RESTController = _CoreManager2.default.getRESTController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + var batches = [[]]; + target.forEach(function (obj) { + if (!obj.id) { + return; + } + batches[batches.length - 1].push(obj); + if (batches[batches.length - 1].length >= 20) { + batches.push([]); + } + }); + if (batches[batches.length - 1].length === 0) { + // If the last batch is empty, remove it + batches.pop(); + } + var deleteCompleted = _ParsePromise2.default.as(); + var errors = []; + batches.forEach(function (batch) { + deleteCompleted = deleteCompleted.then(function () { + return RESTController.request('POST', 'batch', { + requests: batch.map(function (obj) { + return { + method: 'DELETE', + path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), + body: {} + }; + }) + }, options).then(function (results) { + for (var i = 0; i < results.length; i++) { + if (results[i] && results[i].hasOwnProperty('error')) { + var err = new _ParseError2.default(results[i].error.code, results[i].error.error); + err.object = batch[i]; + errors.push(err); + } + } + }); + }); + }); + return deleteCompleted.then(function () { + if (errors.length) { + var aggregate = new _ParseError2.default(_ParseError2.default.AGGREGATE_ERROR); + aggregate.errors = errors; + return _ParsePromise2.default.error(aggregate); + } + return _ParsePromise2.default.as(target); + }); + } else if (target instanceof ParseObject) { + return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function () { + return _ParsePromise2.default.as(target); + }); + } + return _ParsePromise2.default.as(target); + }, + save: function (target, options) { + var RESTController = _CoreManager2.default.getRESTController(); + var stateController = _CoreManager2.default.getObjectStateController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + + var unsaved = target.concat(); + for (var i = 0; i < target.length; i++) { + if (target[i] instanceof ParseObject) { + unsaved = unsaved.concat((0, _unsavedChildren2.default)(target[i], true)); + } + } + unsaved = (0, _unique2.default)(unsaved); + + var filesSaved = _ParsePromise2.default.as(); + var pending = []; + unsaved.forEach(function (el) { + if (el instanceof _ParseFile2.default) { + filesSaved = filesSaved.then(function () { + return el.save(); + }); + } else if (el instanceof ParseObject) { + pending.push(el); + } + }); + + return filesSaved.then(function () { + var objectError = null; + return _ParsePromise2.default._continueWhile(function () { + return pending.length > 0; + }, function () { + var batch = []; + var nextPending = []; + pending.forEach(function (el) { + if (batch.length < 20 && (0, _canBeSerialized2.default)(el)) { + batch.push(el); + } else { + nextPending.push(el); + } + }); + pending = nextPending; + if (batch.length < 1) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); + } + + // Queue up tasks for each object in the batch. + // When every task is ready, the API request will execute + var batchReturned = new _ParsePromise2.default(); + var batchReady = []; + var batchTasks = []; + batch.forEach(function (obj, index) { + var ready = new _ParsePromise2.default(); + batchReady.push(ready); + + stateController.pushPendingState(obj._getStateIdentifier()); + batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { + ready.resolve(); + return batchReturned.then(function (responses, status) { + if (responses[index].hasOwnProperty('success')) { + obj._handleSaveResponse(responses[index].success, status); + } else { + if (!objectError && responses[index].hasOwnProperty('error')) { + var serverError = responses[index].error; + objectError = new _ParseError2.default(serverError.code, serverError.error); + // Cancel the rest of the save + pending = []; + } + obj._handleSaveError(); + } + }); + })); + }); + + _ParsePromise2.default.when(batchReady).then(function () { + // Kick off the batch request + return RESTController.request('POST', 'batch', { + requests: batch.map(function (obj) { + var params = obj._getSaveParams(); + params.path = getServerUrlPath() + params.path; + return params; + }) + }, options); + }).then(function (response, status, xhr) { + batchReturned.resolve(response, status); + }); + + return _ParsePromise2.default.when(batchTasks); + }).then(function () { + if (objectError) { + return _ParsePromise2.default.error(objectError); + } + return _ParsePromise2.default.as(target); + }); + }); + } else if (target instanceof ParseObject) { + // copying target lets Flow guarantee the pointer isn't modified elsewhere + var targetCopy = target; + var task = function () { + var params = targetCopy._getSaveParams(); + return RESTController.request(params.method, params.path, params.body, options).then(function (response, status) { + targetCopy._handleSaveResponse(response, status); + }, function (error) { + targetCopy._handleSaveError(); + return _ParsePromise2.default.error(error); + }); + }; + + stateController.pushPendingState(target._getStateIdentifier()); + return stateController.enqueueTask(target._getStateIdentifier(), task).then(function () { + return target; + }, function (error) { + return _ParsePromise2.default.error(error); + }); + } + return _ParsePromise2.default.as(); + } +}; + +_CoreManager2.default.setObjectController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseOp.js b/lib/browser/ParseOp.js new file mode 100644 index 000000000..1eba19303 --- /dev/null +++ b/lib/browser/ParseOp.js @@ -0,0 +1,579 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.RelationOp = exports.RemoveOp = exports.AddUniqueOp = exports.AddOp = exports.IncrementOp = exports.UnsetOp = exports.SetOp = exports.Op = undefined; + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +exports.opFromJSON = opFromJSON; + +var _arrayContainsObject = require('./arrayContainsObject'); + +var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _unique = require('./unique'); + +var _unique2 = _interopRequireDefault(_unique); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function opFromJSON(json) { + if (!json || !json.__op) { + return null; + } + switch (json.__op) { + case 'Delete': + return new UnsetOp(); + case 'Increment': + return new IncrementOp(json.amount); + case 'Add': + return new AddOp((0, _decode2.default)(json.objects)); + case 'AddUnique': + return new AddUniqueOp((0, _decode2.default)(json.objects)); + case 'Remove': + return new RemoveOp((0, _decode2.default)(json.objects)); + case 'AddRelation': + var toAdd = (0, _decode2.default)(json.objects); + if (!Array.isArray(toAdd)) { + return new RelationOp([], []); + } + return new RelationOp(toAdd, []); + case 'RemoveRelation': + var toRemove = (0, _decode2.default)(json.objects); + if (!Array.isArray(toRemove)) { + return new RelationOp([], []); + } + return new RelationOp([], toRemove); + case 'Batch': + var toAdd = []; + var toRemove = []; + for (var i = 0; i < json.ops.length; i++) { + if (json.ops[i].__op === 'AddRelation') { + toAdd = toAdd.concat((0, _decode2.default)(json.ops[i].objects)); + } else if (json.ops[i].__op === 'RemoveRelation') { + toRemove = toRemove.concat((0, _decode2.default)(json.ops[i].objects)); + } + } + return new RelationOp(toAdd, toRemove); + } + return null; +} + +var Op = exports.Op = function () { + function Op() { + (0, _classCallCheck3.default)(this, Op); + } + + (0, _createClass3.default)(Op, [{ + key: 'applyTo', + + // Empty parent class + value: function (value) {} + }, { + key: 'mergeWith', + value: function (previous) {} + }, { + key: 'toJSON', + value: function () {} + }]); + return Op; +}(); + +var SetOp = exports.SetOp = function (_Op) { + (0, _inherits3.default)(SetOp, _Op); + + function SetOp(value) { + (0, _classCallCheck3.default)(this, SetOp); + + var _this = (0, _possibleConstructorReturn3.default)(this, (SetOp.__proto__ || (0, _getPrototypeOf2.default)(SetOp)).call(this)); + + _this._value = value; + return _this; + } + + (0, _createClass3.default)(SetOp, [{ + key: 'applyTo', + value: function (value) { + return this._value; + } + }, { + key: 'mergeWith', + value: function (previous) { + return new SetOp(this._value); + } + }, { + key: 'toJSON', + value: function () { + return (0, _encode2.default)(this._value, false, true); + } + }]); + return SetOp; +}(Op); + +var UnsetOp = exports.UnsetOp = function (_Op2) { + (0, _inherits3.default)(UnsetOp, _Op2); + + function UnsetOp() { + (0, _classCallCheck3.default)(this, UnsetOp); + return (0, _possibleConstructorReturn3.default)(this, (UnsetOp.__proto__ || (0, _getPrototypeOf2.default)(UnsetOp)).apply(this, arguments)); + } + + (0, _createClass3.default)(UnsetOp, [{ + key: 'applyTo', + value: function (value) { + return undefined; + } + }, { + key: 'mergeWith', + value: function (previous) { + return new UnsetOp(); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Delete' }; + } + }]); + return UnsetOp; +}(Op); + +var IncrementOp = exports.IncrementOp = function (_Op3) { + (0, _inherits3.default)(IncrementOp, _Op3); + + function IncrementOp(amount) { + (0, _classCallCheck3.default)(this, IncrementOp); + + var _this3 = (0, _possibleConstructorReturn3.default)(this, (IncrementOp.__proto__ || (0, _getPrototypeOf2.default)(IncrementOp)).call(this)); + + if (typeof amount !== 'number') { + throw new TypeError('Increment Op must be initialized with a numeric amount.'); + } + _this3._amount = amount; + return _this3; + } + + (0, _createClass3.default)(IncrementOp, [{ + key: 'applyTo', + value: function (value) { + if (typeof value === 'undefined') { + return this._amount; + } + if (typeof value !== 'number') { + throw new TypeError('Cannot increment a non-numeric value.'); + } + return this._amount + value; + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._amount); + } + if (previous instanceof IncrementOp) { + return new IncrementOp(this.applyTo(previous._amount)); + } + throw new Error('Cannot merge Increment Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Increment', amount: this._amount }; + } + }]); + return IncrementOp; +}(Op); + +var AddOp = exports.AddOp = function (_Op4) { + (0, _inherits3.default)(AddOp, _Op4); + + function AddOp(value) { + (0, _classCallCheck3.default)(this, AddOp); + + var _this4 = (0, _possibleConstructorReturn3.default)(this, (AddOp.__proto__ || (0, _getPrototypeOf2.default)(AddOp)).call(this)); + + _this4._value = Array.isArray(value) ? value : [value]; + return _this4; + } + + (0, _createClass3.default)(AddOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return this._value; + } + if (Array.isArray(value)) { + return value.concat(this._value); + } + throw new Error('Cannot add elements to a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddOp) { + return new AddOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge Add Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Add', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return AddOp; +}(Op); + +var AddUniqueOp = exports.AddUniqueOp = function (_Op5) { + (0, _inherits3.default)(AddUniqueOp, _Op5); + + function AddUniqueOp(value) { + (0, _classCallCheck3.default)(this, AddUniqueOp); + + var _this5 = (0, _possibleConstructorReturn3.default)(this, (AddUniqueOp.__proto__ || (0, _getPrototypeOf2.default)(AddUniqueOp)).call(this)); + + _this5._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); + return _this5; + } + + (0, _createClass3.default)(AddUniqueOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return this._value || []; + } + if (Array.isArray(value)) { + // copying value lets Flow guarantee the pointer isn't modified elsewhere + var valueCopy = value; + var toAdd = []; + this._value.forEach(function (v) { + if (v instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(valueCopy, v)) { + toAdd.push(v); + } + } else { + if (valueCopy.indexOf(v) < 0) { + toAdd.push(v); + } + } + }); + return value.concat(toAdd); + } + throw new Error('Cannot add elements to a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddUniqueOp) { + return new AddUniqueOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge AddUnique Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'AddUnique', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return AddUniqueOp; +}(Op); + +var RemoveOp = exports.RemoveOp = function (_Op6) { + (0, _inherits3.default)(RemoveOp, _Op6); + + function RemoveOp(value) { + (0, _classCallCheck3.default)(this, RemoveOp); + + var _this6 = (0, _possibleConstructorReturn3.default)(this, (RemoveOp.__proto__ || (0, _getPrototypeOf2.default)(RemoveOp)).call(this)); + + _this6._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); + return _this6; + } + + (0, _createClass3.default)(RemoveOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return []; + } + if (Array.isArray(value)) { + var i = value.indexOf(this._value); + var removed = value.concat([]); + for (var i = 0; i < this._value.length; i++) { + var index = removed.indexOf(this._value[i]); + while (index > -1) { + removed.splice(index, 1); + index = removed.indexOf(this._value[i]); + } + if (this._value[i] instanceof _ParseObject2.default && this._value[i].id) { + for (var j = 0; j < removed.length; j++) { + if (removed[j] instanceof _ParseObject2.default && this._value[i].id === removed[j].id) { + removed.splice(j, 1); + j--; + } + } + } + } + return removed; + } + throw new Error('Cannot remove elements from a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new UnsetOp(); + } + if (previous instanceof RemoveOp) { + var uniques = previous._value.concat([]); + for (var i = 0; i < this._value.length; i++) { + if (this._value[i] instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(uniques, this._value[i])) { + uniques.push(this._value[i]); + } + } else { + if (uniques.indexOf(this._value[i]) < 0) { + uniques.push(this._value[i]); + } + } + } + return new RemoveOp(uniques); + } + throw new Error('Cannot merge Remove Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Remove', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return RemoveOp; +}(Op); + +var RelationOp = exports.RelationOp = function (_Op7) { + (0, _inherits3.default)(RelationOp, _Op7); + + function RelationOp(adds, removes) { + (0, _classCallCheck3.default)(this, RelationOp); + + var _this7 = (0, _possibleConstructorReturn3.default)(this, (RelationOp.__proto__ || (0, _getPrototypeOf2.default)(RelationOp)).call(this)); + + _this7._targetClassName = null; + + if (Array.isArray(adds)) { + _this7.relationsToAdd = (0, _unique2.default)(adds.map(_this7._extractId, _this7)); + } + + if (Array.isArray(removes)) { + _this7.relationsToRemove = (0, _unique2.default)(removes.map(_this7._extractId, _this7)); + } + return _this7; + } + + (0, _createClass3.default)(RelationOp, [{ + key: '_extractId', + value: function (obj) { + if (typeof obj === 'string') { + return obj; + } + if (!obj.id) { + throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); + } + if (!this._targetClassName) { + this._targetClassName = obj.className; + } + if (this._targetClassName !== obj.className) { + throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); + } + return obj.id; + } + }, { + key: 'applyTo', + value: function (value, object, key) { + if (!value) { + if (!object || !key) { + throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); + } + var parent = new _ParseObject2.default(object.className); + if (object.id && object.id.indexOf('local') === 0) { + parent._localId = object.id; + } else if (object.id) { + parent.id = object.id; + } + var relation = new _ParseRelation2.default(parent, key); + relation.targetClassName = this._targetClassName; + return relation; + } + if (value instanceof _ParseRelation2.default) { + if (this._targetClassName) { + if (value.targetClassName) { + if (this._targetClassName !== value.targetClassName) { + throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); + } + } else { + value.targetClassName = this._targetClassName; + } + } + return value; + } else { + throw new Error('Relation cannot be applied to a non-relation field'); + } + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } else if (previous instanceof UnsetOp) { + throw new Error('You cannot modify a relation after deleting it.'); + } else if (previous instanceof RelationOp) { + if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { + throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); + } + var newAdd = previous.relationsToAdd.concat([]); + this.relationsToRemove.forEach(function (r) { + var index = newAdd.indexOf(r); + if (index > -1) { + newAdd.splice(index, 1); + } + }); + this.relationsToAdd.forEach(function (r) { + var index = newAdd.indexOf(r); + if (index < 0) { + newAdd.push(r); + } + }); + + var newRemove = previous.relationsToRemove.concat([]); + this.relationsToAdd.forEach(function (r) { + var index = newRemove.indexOf(r); + if (index > -1) { + newRemove.splice(index, 1); + } + }); + this.relationsToRemove.forEach(function (r) { + var index = newRemove.indexOf(r); + if (index < 0) { + newRemove.push(r); + } + }); + + var newRelation = new RelationOp(newAdd, newRemove); + newRelation._targetClassName = this._targetClassName; + return newRelation; + } + throw new Error('Cannot merge Relation Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + var _this8 = this; + + var idToPointer = function (id) { + return { + __type: 'Pointer', + className: _this8._targetClassName, + objectId: id + }; + }; + + var adds = null; + var removes = null; + var pointers = null; + + if (this.relationsToAdd.length > 0) { + pointers = this.relationsToAdd.map(idToPointer); + adds = { __op: 'AddRelation', objects: pointers }; + } + if (this.relationsToRemove.length > 0) { + pointers = this.relationsToRemove.map(idToPointer); + removes = { __op: 'RemoveRelation', objects: pointers }; + } + + if (adds && removes) { + return { __op: 'Batch', ops: [adds, removes] }; + } + + return adds || removes || {}; + } + }]); + return RelationOp; +}(Op); \ No newline at end of file diff --git a/lib/browser/ParsePromise.js b/lib/browser/ParsePromise.js new file mode 100644 index 000000000..a79b4afee --- /dev/null +++ b/lib/browser/ParsePromise.js @@ -0,0 +1,740 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getIterator2 = require('babel-runtime/core-js/get-iterator'); + +var _getIterator3 = _interopRequireDefault(_getIterator2); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var _isPromisesAPlusCompliant = true; + +/** + * A Promise is returned by async methods as a hook to provide callbacks to be + * called when the async task is fulfilled. + * + *

      Typical usage would be like:

      + *    query.find().then(function(results) {
      + *      results[0].set("foo", "bar");
      + *      return results[0].saveAsync();
      + *    }).then(function(result) {
      + *      console.log("Updated " + result.id);
      + *    });
      + * 

      + * + * @class Parse.Promise + * @constructor + */ + +var ParsePromise = function () { + function ParsePromise(executor) { + (0, _classCallCheck3.default)(this, ParsePromise); + + this._resolved = false; + this._rejected = false; + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + + if (typeof executor === 'function') { + executor(this.resolve.bind(this), this.reject.bind(this)); + } + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method resolve + * @param {Object} result the result to pass to the callbacks. + */ + + (0, _createClass3.default)(ParsePromise, [{ + key: 'resolve', + value: function () { + if (this._resolved || this._rejected) { + throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._resolved = true; + + for (var _len = arguments.length, results = Array(_len), _key = 0; _key < _len; _key++) { + results[_key] = arguments[_key]; + } + + this._result = results; + for (var i = 0; i < this._resolvedCallbacks.length; i++) { + this._resolvedCallbacks[i].apply(this, results); + } + + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method reject + * @param {Object} error the error to pass to the callbacks. + */ + + }, { + key: 'reject', + value: function (error) { + if (this._resolved || this._rejected) { + throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._rejected = true; + this._error = error; + for (var i = 0; i < this._rejectedCallbacks.length; i++) { + this._rejectedCallbacks[i](error); + } + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Adds callbacks to be called when this promise is fulfilled. Returns a new + * Promise that will be fulfilled when the callback is complete. It allows + * chaining. If the callback itself returns a Promise, then the one returned + * by "then" will not be fulfilled until that one returned by the callback + * is fulfilled. + * @method then + * @param {Function} resolvedCallback Function that is called when this + * Promise is resolved. Once the callback is complete, then the Promise + * returned by "then" will also be fulfilled. + * @param {Function} rejectedCallback Function that is called when this + * Promise is rejected with an error. Once the callback is complete, then + * the promise returned by "then" with be resolved successfully. If + * rejectedCallback is null, or it returns a rejected Promise, then the + * Promise returned by "then" will be rejected with that error. + * @return {Parse.Promise} A new Promise that will be fulfilled after this + * Promise is fulfilled and either callback has completed. If the callback + * returned a Promise, then this Promise will not be fulfilled until that + * one is. + */ + + }, { + key: 'then', + value: function (resolvedCallback, rejectedCallback) { + var _this = this; + + var promise = new ParsePromise(); + + var wrappedResolvedCallback = function () { + for (var _len2 = arguments.length, results = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + results[_key2] = arguments[_key2]; + } + + if (typeof resolvedCallback === 'function') { + if (_isPromisesAPlusCompliant) { + try { + results = [resolvedCallback.apply(this, results)]; + } catch (e) { + results = [ParsePromise.error(e)]; + } + } else { + results = [resolvedCallback.apply(this, results)]; + } + } + if (results.length === 1 && ParsePromise.is(results[0])) { + results[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + promise.resolve.apply(promise, results); + } + }; + + var wrappedRejectedCallback = function (error) { + var result = []; + if (typeof rejectedCallback === 'function') { + if (_isPromisesAPlusCompliant) { + try { + result = [rejectedCallback(error)]; + } catch (e) { + result = [ParsePromise.error(e)]; + } + } else { + result = [rejectedCallback(error)]; + } + if (result.length === 1 && ParsePromise.is(result[0])) { + result[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + if (_isPromisesAPlusCompliant) { + promise.resolve.apply(promise, result); + } else { + promise.reject(result[0]); + } + } + } else { + promise.reject(error); + } + }; + + var runLater = function (fn) { + fn.call(); + }; + if (_isPromisesAPlusCompliant) { + if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { + runLater = function (fn) { + process.nextTick(fn); + }; + } else if (typeof setTimeout === 'function') { + runLater = function (fn) { + setTimeout(fn, 0); + }; + } + } + + if (this._resolved) { + runLater(function () { + wrappedResolvedCallback.apply(_this, _this._result); + }); + } else if (this._rejected) { + runLater(function () { + wrappedRejectedCallback(_this._error); + }); + } else { + this._resolvedCallbacks.push(wrappedResolvedCallback); + this._rejectedCallbacks.push(wrappedRejectedCallback); + } + + return promise; + } + + /** + * Add handlers to be called when the promise + * is either resolved or rejected + * @method always + */ + + }, { + key: 'always', + value: function (callback) { + return this.then(callback, callback); + } + + /** + * Add handlers to be called when the Promise object is resolved + * @method done + */ + + }, { + key: 'done', + value: function (callback) { + return this.then(callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * Alias for catch(). + * @method fail + */ + + }, { + key: 'fail', + value: function (callback) { + return this.then(null, callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * @method catch + */ + + }, { + key: 'catch', + value: function (callback) { + return this.then(null, callback); + } + + /** + * Run the given callbacks after this promise is fulfilled. + * @method _thenRunCallbacks + * @param optionsOrCallback {} A Backbone-style options callback, or a + * callback function. If this is an options object and contains a "model" + * attributes, that will be passed to error callbacks as the first argument. + * @param model {} If truthy, this will be passed as the first result of + * error callbacks. This is for Backbone-compatability. + * @return {Parse.Promise} A promise that will be resolved after the + * callbacks are run, with the same result as this. + */ + + }, { + key: '_thenRunCallbacks', + value: function (optionsOrCallback, model) { + var options = {}; + if (typeof optionsOrCallback === 'function') { + options.success = function (result) { + optionsOrCallback(result, null); + }; + options.error = function (error) { + optionsOrCallback(null, error); + }; + } else if ((typeof optionsOrCallback === 'undefined' ? 'undefined' : (0, _typeof3.default)(optionsOrCallback)) === 'object') { + if (typeof optionsOrCallback.success === 'function') { + options.success = optionsOrCallback.success; + } + if (typeof optionsOrCallback.error === 'function') { + options.error = optionsOrCallback.error; + } + } + + return this.then(function () { + for (var _len3 = arguments.length, results = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + results[_key3] = arguments[_key3]; + } + + if (options.success) { + options.success.apply(this, results); + } + return ParsePromise.as.apply(ParsePromise, arguments); + }, function (error) { + if (options.error) { + if (typeof model !== 'undefined') { + options.error(model, error); + } else { + options.error(error); + } + } + // By explicitly returning a rejected Promise, this will work with + // either jQuery or Promises/A+ semantics. + return ParsePromise.error(error); + }); + } + + /** + * Adds a callback function that should be called regardless of whether + * this promise failed or succeeded. The callback will be given either the + * array of results for its first argument, or the error as its second, + * depending on whether this Promise was rejected or resolved. Returns a + * new Promise, like "then" would. + * @method _continueWith + * @param {Function} continuation the callback. + */ + + }, { + key: '_continueWith', + value: function (continuation) { + return this.then(function () { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + return continuation(args, null); + }, function (error) { + return continuation(null, error); + }); + } + + /** + * Returns true iff the given object fulfils the Promise interface. + * @method is + * @param {Object} promise The object to test + * @static + * @return {Boolean} + */ + + }], [{ + key: 'is', + value: function (promise) { + return promise != null && typeof promise.then === 'function'; + } + + /** + * Returns a new promise that is resolved with a given value. + * @method as + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'as', + value: function () { + var promise = new ParsePromise(); + + for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + values[_key5] = arguments[_key5]; + } + + promise.resolve.apply(promise, values); + return promise; + } + + /** + * Returns a new promise that is resolved with a given value. + * If that value is a thenable Promise (has a .then() prototype + * method), the new promise will be chained to the end of the + * value. + * @method resolve + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'resolve', + value: function (value) { + return new ParsePromise(function (resolve, reject) { + if (ParsePromise.is(value)) { + value.then(resolve, reject); + } else { + resolve(value); + } + }); + } + + /** + * Returns a new promise that is rejected with a given error. + * @method error + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'error', + value: function () { + var promise = new ParsePromise(); + + for (var _len6 = arguments.length, errors = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + errors[_key6] = arguments[_key6]; + } + + promise.reject.apply(promise, errors); + return promise; + } + + /** + * Returns a new promise that is rejected with a given error. + * This is an alias for Parse.Promise.error, for compliance with + * the ES6 implementation. + * @method reject + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'reject', + value: function () { + for (var _len7 = arguments.length, errors = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + errors[_key7] = arguments[_key7]; + } + + return ParsePromise.error.apply(null, errors); + } + + /** + * Returns a new promise that is fulfilled when all of the input promises + * are resolved. If any promise in the list fails, then the returned promise + * will be rejected with an array containing the error from each promise. + * If they all succeed, then the returned promise will succeed, with the + * results being the results of all the input + * promises. For example:
      +     *   var p1 = Parse.Promise.as(1);
      +     *   var p2 = Parse.Promise.as(2);
      +     *   var p3 = Parse.Promise.as(3);
      +     *
      +     *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
      +     *     console.log(r1);  // prints 1
      +     *     console.log(r2);  // prints 2
      +     *     console.log(r3);  // prints 3
      +     *   });
      + * + * The input promises can also be specified as an array:
      +     *   var promises = [p1, p2, p3];
      +     *   Parse.Promise.when(promises).then(function(results) {
      +     *     console.log(results);  // prints [1,2,3]
      +     *   });
      +     * 
      + * @method when + * @param {Array} promises a list of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'when', + value: function (promises) { + var objects; + var arrayArgument = Array.isArray(promises); + if (arrayArgument) { + objects = promises; + } else { + objects = arguments; + } + + var total = objects.length; + var hadError = false; + var results = []; + var returnValue = arrayArgument ? [results] : results; + var errors = []; + results.length = objects.length; + errors.length = objects.length; + + if (total === 0) { + return ParsePromise.as.apply(this, returnValue); + } + + var promise = new ParsePromise(); + + var resolveOne = function () { + total--; + if (total <= 0) { + if (hadError) { + promise.reject(errors); + } else { + promise.resolve.apply(promise, returnValue); + } + } + }; + + var chain = function (object, index) { + if (ParsePromise.is(object)) { + object.then(function (result) { + results[index] = result; + resolveOne(); + }, function (error) { + errors[index] = error; + hadError = true; + resolveOne(); + }); + } else { + results[i] = object; + resolveOne(); + } + }; + for (var i = 0; i < objects.length; i++) { + chain(objects[i], i); + } + + return promise; + } + + /** + * Returns a new promise that is fulfilled when all of the promises in the + * iterable argument are resolved. If any promise in the list fails, then + * the returned promise will be immediately rejected with the reason that + * single promise rejected. If they all succeed, then the returned promise + * will succeed, with the results being the results of all the input + * promises. If the iterable provided is empty, the returned promise will + * be immediately resolved. + * + * For example:
      +     *   var p1 = Parse.Promise.as(1);
      +     *   var p2 = Parse.Promise.as(2);
      +     *   var p3 = Parse.Promise.as(3);
      +     *
      +     *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
      +     *     console.log(r1);  // prints 1
      +     *     console.log(r2);  // prints 2
      +     *     console.log(r3);  // prints 3
      +     *   });
      + * + * @method all + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'all', + value: function (promises) { + var total = 0; + var objects = []; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = (0, _getIterator3.default)(promises), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var p = _step.value; + + objects[total++] = p; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (total === 0) { + return ParsePromise.as([]); + } + + var hadError = false; + var promise = new ParsePromise(); + var resolved = 0; + var results = []; + objects.forEach(function (object, i) { + if (ParsePromise.is(object)) { + object.then(function (result) { + if (hadError) { + return false; + } + results[i] = result; + resolved++; + if (resolved >= total) { + promise.resolve(results); + } + }, function (error) { + // Reject immediately + promise.reject(error); + hadError = true; + }); + } else { + results[i] = object; + resolved++; + if (!hadError && resolved >= total) { + promise.resolve(results); + } + } + }); + + return promise; + } + + /** + * Returns a new promise that is immediately fulfilled when any of the + * promises in the iterable argument are resolved or rejected. If the + * first promise to complete is resolved, the returned promise will be + * resolved with the same value. Likewise, if the first promise to + * complete is rejected, the returned promise will be rejected with the + * same reason. + * + * @method race + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'race', + value: function (promises) { + var completed = false; + var promise = new ParsePromise(); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = (0, _getIterator3.default)(promises), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var p = _step2.value; + + if (ParsePromise.is(p)) { + p.then(function (result) { + if (completed) { + return; + } + completed = true; + promise.resolve(result); + }, function (error) { + if (completed) { + return; + } + completed = true; + promise.reject(error); + }); + } else if (!completed) { + completed = true; + promise.resolve(p); + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return promise; + } + + /** + * Runs the given asyncFunction repeatedly, as long as the predicate + * function returns a truthy value. Stops repeating if asyncFunction returns + * a rejected promise. + * @method _continueWhile + * @param {Function} predicate should return false when ready to stop. + * @param {Function} asyncFunction should return a Promise. + * @static + */ + + }, { + key: '_continueWhile', + value: function (predicate, asyncFunction) { + if (predicate()) { + return asyncFunction().then(function () { + return ParsePromise._continueWhile(predicate, asyncFunction); + }); + } + return ParsePromise.as(); + } + }, { + key: 'isPromisesAPlusCompliant', + value: function () { + return _isPromisesAPlusCompliant; + } + }, { + key: 'enableAPlusCompliant', + value: function () { + _isPromisesAPlusCompliant = true; + } + }, { + key: 'disableAPlusCompliant', + value: function () { + _isPromisesAPlusCompliant = false; + } + }]); + return ParsePromise; +}(); + +exports.default = ParsePromise; \ No newline at end of file diff --git a/lib/browser/ParseQuery.js b/lib/browser/ParseQuery.js new file mode 100644 index 000000000..664f5a737 --- /dev/null +++ b/lib/browser/ParseQuery.js @@ -0,0 +1,1340 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Converts a string into a regex that matches it. + * Surrounding with \Q .. \E does this, we just need to escape any \E's in + * the text separately. + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function quote(s) { + return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; +} + +/** + * Handles pre-populating the result data of a query with select fields, + * making sure that the data object contains keys for all objects that have + * been requested with a select, so that our cached state updates correctly. + */ +function handleSelectResult(data, select) { + var serverDataMask = {}; + + select.forEach(function (field) { + var hasSubObjectSelect = field.indexOf(".") !== -1; + if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { + // this field was selected, but is missing from the retrieved data + data[field] = undefined; + } else if (hasSubObjectSelect) { + // this field references a sub-object, + // so we need to walk down the path components + var pathComponents = field.split("."); + var obj = data; + var serverMask = serverDataMask; + + pathComponents.forEach(function (component, index, arr) { + // add keys if the expected data is missing + if (!obj[component]) { + obj[component] = index == arr.length - 1 ? undefined : {}; + } + obj = obj[component]; + + //add this path component to the server mask so we can fill it in later if needed + if (index < arr.length - 1) { + if (!serverMask[component]) { + serverMask[component] = {}; + } + } + }); + } + }); + + if ((0, _keys2.default)(serverDataMask).length > 0) { + var copyMissingDataWithMask = function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { + //copy missing elements at this level + if (copyThisLevel) { + for (var key in src) { + if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + } + for (var key in mask) { + //traverse into objects as needed + copyMissingDataWithMask(src[key], dest[key], mask[key], true); + } + }; + + // When selecting from sub-objects, we don't want to blow away the missing + // information that we may have retrieved before. We've already added any + // missing selected keys to sub-objects, but we still need to add in the + // data for any previously retrieved sub-objects that were not selected. + + var serverData = _CoreManager2.default.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); + + copyMissingDataWithMask(serverData, data, serverDataMask, false); + } +} + +/** + * Creates a new parse Parse.Query for the given Parse.Object subclass. + * @class Parse.Query + * @constructor + * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. + * + *

      Parse.Query defines a query that is used to fetch Parse.Objects. The + * most common use case is finding all objects that match a query through the + * find method. For example, this sample code fetches all objects + * of class MyClass. It calls a different function depending on + * whether the fetch succeeded or not. + * + *

      + * var query = new Parse.Query(MyClass);
      + * query.find({
      + *   success: function(results) {
      + *     // results is an array of Parse.Object.
      + *   },
      + *
      + *   error: function(error) {
      + *     // error is an instance of Parse.Error.
      + *   }
      + * });

      + * + *

      A Parse.Query can also be used to retrieve a single object whose id is + * known, through the get method. For example, this sample code fetches an + * object of class MyClass and id myId. It calls a + * different function depending on whether the fetch succeeded or not. + * + *

      + * var query = new Parse.Query(MyClass);
      + * query.get(myId, {
      + *   success: function(object) {
      + *     // object is an instance of Parse.Object.
      + *   },
      + *
      + *   error: function(object, error) {
      + *     // error is an instance of Parse.Error.
      + *   }
      + * });

      + * + *

      A Parse.Query can also be used to count the number of objects that match + * the query without retrieving all of those objects. For example, this + * sample code counts the number of objects of the class MyClass + *

      + * var query = new Parse.Query(MyClass);
      + * query.count({
      + *   success: function(number) {
      + *     // There are number instances of MyClass.
      + *   },
      + *
      + *   error: function(error) {
      + *     // error is an instance of Parse.Error.
      + *   }
      + * });

      + */ + +var ParseQuery = function () { + function ParseQuery(objectClass) { + (0, _classCallCheck3.default)(this, ParseQuery); + + if (typeof objectClass === 'string') { + if (objectClass === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { + this.className = '_User'; + } else { + this.className = objectClass; + } + } else if (objectClass instanceof _ParseObject2.default) { + this.className = objectClass.className; + } else if (typeof objectClass === 'function') { + if (typeof objectClass.className === 'string') { + this.className = objectClass.className; + } else { + var obj = new objectClass(); + this.className = obj.className; + } + } else { + throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); + } + + this._where = {}; + this._include = []; + this._limit = -1; // negative limit is not sent in the server request + this._skip = 0; + this._extraOptions = {}; + } + + /** + * Adds constraint that at least one of the passed in queries matches. + * @method _orQuery + * @param {Array} queries + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + (0, _createClass3.default)(ParseQuery, [{ + key: '_orQuery', + value: function (queries) { + var queryJSON = queries.map(function (q) { + return q.toJSON().where; + }); + + this._where.$or = queryJSON; + return this; + } + + /** + * Helper for condition queries + */ + + }, { + key: '_addCondition', + value: function (key, condition, value) { + if (!this._where[key] || typeof this._where[key] === 'string') { + this._where[key] = {}; + } + this._where[key][condition] = (0, _encode2.default)(value, false, true); + return this; + } + + /** + * Converts string for regular expression at the beginning + */ + + }, { + key: '_regexStartWith', + value: function (string) { + return '^' + quote(string); + } + + /** + * Returns a JSON representation of this query. + * @method toJSON + * @return {Object} The JSON representation of the query. + */ + + }, { + key: 'toJSON', + value: function () { + var params = { + where: this._where + }; + + if (this._include.length) { + params.include = this._include.join(','); + } + if (this._select) { + params.keys = this._select.join(','); + } + if (this._limit >= 0) { + params.limit = this._limit; + } + if (this._skip > 0) { + params.skip = this._skip; + } + if (this._order) { + params.order = this._order.join(','); + } + for (var key in this._extraOptions) { + params[key] = this._extraOptions[key]; + } + + return params; + } + + /** + * Constructs a Parse.Object whose id is already known by fetching data from + * the server. Either options.success or options.error is called when the + * find completes. + * + * @method get + * @param {String} objectId The id of the object to be fetched. + * @param {Object} options A Backbone-style options object. + * Valid options are:
        + *
      • success: A Backbone-style success callback + *
      • error: An Backbone-style error callback. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * + * @return {Parse.Promise} A promise that is resolved with the result when + * the query completes. + */ + + }, { + key: 'get', + value: function (objectId, options) { + this.equalTo('objectId', objectId); + + var firstOptions = {}; + if (options && options.hasOwnProperty('useMasterKey')) { + firstOptions.useMasterKey = options.useMasterKey; + } + if (options && options.hasOwnProperty('sessionToken')) { + firstOptions.sessionToken = options.sessionToken; + } + + return this.first(firstOptions).then(function (response) { + if (response) { + return response; + } + + var errorObject = new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'Object not found.'); + return _ParsePromise2.default.error(errorObject); + })._thenRunCallbacks(options, null); + } + + /** + * Retrieves a list of ParseObjects that satisfy this query. + * Either options.success or options.error is called when the find + * completes. + * + * @method find + * @param {Object} options A Backbone-style options object. Valid options + * are:
        + *
      • success: Function to call when the find completes successfully. + *
      • error: Function to call when the find fails. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * + * @return {Parse.Promise} A promise that is resolved with the results when + * the query completes. + */ + + }, { + key: 'find', + value: function (options) { + var _this2 = this; + + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var select = this._select; + + return controller.find(this.className, this.toJSON(), findOptions).then(function (response) { + return response.results.map(function (data) { + // In cases of relations, the server may send back a className + // on the top level of the payload + var override = response.className || _this2.className; + if (!data.className) { + data.className = override; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(data, select); + } + + return _ParseObject2.default.fromJSON(data, !select); + }); + })._thenRunCallbacks(options); + } + + /** + * Counts the number of objects that match this query. + * Either options.success or options.error is called when the count + * completes. + * + * @method count + * @param {Object} options A Backbone-style options object. Valid options + * are:
        + *
      • success: Function to call when the count completes successfully. + *
      • error: Function to call when the find fails. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * + * @return {Parse.Promise} A promise that is resolved with the count when + * the query completes. + */ + + }, { + key: 'count', + value: function (options) { + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var params = this.toJSON(); + params.limit = 0; + params.count = 1; + + return controller.find(this.className, params, findOptions).then(function (result) { + return result.count; + })._thenRunCallbacks(options); + } + + /** + * Retrieves at most one Parse.Object that satisfies this query. + * + * Either options.success or options.error is called when it completes. + * success is passed the object if there is one. otherwise, undefined. + * + * @method first + * @param {Object} options A Backbone-style options object. Valid options + * are:
        + *
      • success: Function to call when the find completes successfully. + *
      • error: Function to call when the find fails. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * + * @return {Parse.Promise} A promise that is resolved with the object when + * the query completes. + */ + + }, { + key: 'first', + value: function (options) { + var _this3 = this; + + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var params = this.toJSON(); + params.limit = 1; + + var select = this._select; + + return controller.find(this.className, params, findOptions).then(function (response) { + var objects = response.results; + if (!objects[0]) { + return undefined; + } + if (!objects[0].className) { + objects[0].className = _this3.className; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(objects[0], select); + } + + return _ParseObject2.default.fromJSON(objects[0], !select); + })._thenRunCallbacks(options); + } + + /** + * Iterates over each result of a query, calling a callback for each one. If + * the callback returns a promise, the iteration will not continue until + * that promise has been fulfilled. If the callback returns a rejected + * promise, then iteration will stop with that error. The items are + * processed in an unspecified order. The query may not have any sort order, + * and may not use limit or skip. + * @method each + * @param {Function} callback Callback that will be called with each result + * of the query. + * @param {Object} options A Backbone-style options object. Valid options + * are:
        + *
      • success: Function to call when the iteration completes successfully. + *
      • error: Function to call when the iteration fails. + *
      • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
      • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
      + * @return {Parse.Promise} A promise that will be fulfilled once the + * iteration has completed. + */ + + }, { + key: 'each', + value: function (callback, options) { + options = options || {}; + + if (this._order || this._skip || this._limit >= 0) { + return _ParsePromise2.default.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); + } + + new _ParsePromise2.default(); + + + var query = new ParseQuery(this.className); + // We can override the batch size from the options. + // This is undocumented, but useful for testing. + query._limit = options.batchSize || 100; + query._include = this._include.map(function (i) { + return i; + }); + if (this._select) { + query._select = this._select.map(function (s) { + return s; + }); + } + + query._where = {}; + for (var attr in this._where) { + var val = this._where[attr]; + if (Array.isArray(val)) { + query._where[attr] = val.map(function (v) { + return v; + }); + } else if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object') { + var conditionMap = {}; + query._where[attr] = conditionMap; + for (var cond in val) { + conditionMap[cond] = val[cond]; + } + } else { + query._where[attr] = val; + } + } + + query.ascending('objectId'); + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var finished = false; + return _ParsePromise2.default._continueWhile(function () { + return !finished; + }, function () { + return query.find(findOptions).then(function (results) { + var callbacksDone = _ParsePromise2.default.as(); + results.forEach(function (result) { + callbacksDone = callbacksDone.then(function () { + return callback(result); + }); + }); + + return callbacksDone.then(function () { + if (results.length >= query._limit) { + query.greaterThan('objectId', results[results.length - 1].id); + } else { + finished = true; + } + }); + }); + })._thenRunCallbacks(options); + } + + /** Query Conditions **/ + + /** + * Adds a constraint to the query that requires a particular key's value to + * be equal to the provided value. + * @method equalTo + * @param {String} key The key to check. + * @param value The value that the Parse.Object must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'equalTo', + value: function (key, value) { + if (typeof value === 'undefined') { + return this.doesNotExist(key); + } + + this._where[key] = (0, _encode2.default)(value, false, true); + return this; + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be not equal to the provided value. + * @method notEqualTo + * @param {String} key The key to check. + * @param value The value that must not be equalled. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'notEqualTo', + value: function (key, value) { + return this._addCondition(key, '$ne', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than the provided value. + * @method lessThan + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'lessThan', + value: function (key, value) { + return this._addCondition(key, '$lt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than the provided value. + * @method greaterThan + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'greaterThan', + value: function (key, value) { + return this._addCondition(key, '$gt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than or equal to the provided value. + * @method lessThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'lessThanOrEqualTo', + value: function (key, value) { + return this._addCondition(key, '$lte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than or equal to the provided value. + * @method greaterThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'greaterThanOrEqualTo', + value: function (key, value) { + return this._addCondition(key, '$gte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be contained in the provided list of values. + * @method containedIn + * @param {String} key The key to check. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containedIn', + value: function (key, value) { + return this._addCondition(key, '$in', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * not be contained in the provided list of values. + * @method notContainedIn + * @param {String} key The key to check. + * @param {Array} values The values that will not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'notContainedIn', + value: function (key, value) { + return this._addCondition(key, '$nin', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values. + * @method containsAll + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containsAll', + value: function (key, values) { + return this._addCondition(key, '$all', values); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values starting with given strings. + * @method containsAllStartingWith + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The string values that will match as starting string. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containsAllStartingWith', + value: function (key, values) { + var _this = this; + if (!Array.isArray(values)) { + values = [values]; + } + + values = values.map(function (value) { + return { "$regex": _this._regexStartWith(value) }; + }); + + return this.containsAll(key, values); + } + + /** + * Adds a constraint for finding objects that contain the given key. + * @method exists + * @param {String} key The key that should exist. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'exists', + value: function (key) { + return this._addCondition(key, '$exists', true); + } + + /** + * Adds a constraint for finding objects that do not contain a given key. + * @method doesNotExist + * @param {String} key The key that should not exist + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotExist', + value: function (key) { + return this._addCondition(key, '$exists', false); + } + + /** + * Adds a regular expression constraint for finding string values that match + * the provided regular expression. + * This may be slow for large datasets. + * @method matches + * @param {String} key The key that the string to match is stored in. + * @param {RegExp} regex The regular expression pattern to match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matches', + value: function (key, regex, modifiers) { + this._addCondition(key, '$regex', regex); + if (!modifiers) { + modifiers = ''; + } + if (regex.ignoreCase) { + modifiers += 'i'; + } + if (regex.multiline) { + modifiers += 'm'; + } + if (modifiers.length) { + this._addCondition(key, '$options', modifiers); + } + return this; + } + + /** + * Adds a constraint that requires that a key's value matches a Parse.Query + * constraint. + * @method matchesQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matchesQuery', + value: function (key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$inQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value not matches a + * Parse.Query constraint. + * @method doesNotMatchQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotMatchQuery', + value: function (key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$notInQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value matches a value in + * an object returned by a different Parse.Query. + * @method matchesKeyInQuery + * @param {String} key The key that contains the value that is being + * matched. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matchesKeyInQuery', + value: function (key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$select', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint that requires that a key's value not match a value in + * an object returned by a different Parse.Query. + * @method doesNotMatchKeyInQuery + * @param {String} key The key that contains the value that is being + * excluded. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotMatchKeyInQuery', + value: function (key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$dontSelect', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint for finding string values that contain a provided + * string. This may be slow for large datasets. + * @method contains + * @param {String} key The key that the string to match is stored in. + * @param {String} substring The substring that the value must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'contains', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value)); + } + + /** + * Adds a constraint for finding string values that start with a provided + * string. This query will use the backend index, so it will be fast even + * for large datasets. + * @method startsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} prefix The substring that the value must start with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'startsWith', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', this._regexStartWith(value)); + } + + /** + * Adds a constraint for finding string values that end with a provided + * string. This will be slow for large datasets. + * @method endsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} suffix The substring that the value must end with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'endsWith', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value) + '$'); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given. + * @method near + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'near', + value: function (key, point) { + if (!(point instanceof _ParseGeoPoint2.default)) { + // Try to cast it as a GeoPoint + point = new _ParseGeoPoint2.default(point); + } + return this._addCondition(key, '$nearSphere', point); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * @method withinRadians + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in radians) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinRadians', + value: function (key, point, distance) { + this.near(key, point); + return this._addCondition(key, '$maxDistance', distance); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 3958.8 miles. + * @method withinMiles + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in miles) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinMiles', + value: function (key, point, distance) { + return this.withinRadians(key, point, distance / 3958.8); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 6371.0 kilometers. + * @method withinKilometers + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in kilometers) of results + * to return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinKilometers', + value: function (key, point, distance) { + return this.withinRadians(key, point, distance / 6371.0); + } + + /** + * Adds a constraint to the query that requires a particular key's + * coordinates be contained within a given rectangular geographic bounding + * box. + * @method withinGeoBox + * @param {String} key The key to be constrained. + * @param {Parse.GeoPoint} southwest + * The lower-left inclusive corner of the box. + * @param {Parse.GeoPoint} northeast + * The upper-right inclusive corner of the box. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinGeoBox', + value: function (key, southwest, northeast) { + if (!(southwest instanceof _ParseGeoPoint2.default)) { + southwest = new _ParseGeoPoint2.default(southwest); + } + if (!(northeast instanceof _ParseGeoPoint2.default)) { + northeast = new _ParseGeoPoint2.default(northeast); + } + this._addCondition(key, '$within', { '$box': [southwest, northeast] }); + return this; + } + + /** Query Orderings **/ + + /** + * Sorts the results in ascending order by the given key. + * + * @method ascending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'ascending', + value: function () { + this._order = []; + + for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) { + keys[_key] = arguments[_key]; + } + + return this.addAscending.apply(this, keys); + } + + /** + * Sorts the results in ascending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addAscending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'addAscending', + value: function () { + var _this4 = this; + + if (!this._order) { + this._order = []; + } + + for (var _len2 = arguments.length, keys = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + keys[_key2] = arguments[_key2]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + key = key.join(); + } + _this4._order = _this4._order.concat(key.replace(/\s/g, '').split(',')); + }); + + return this; + } + + /** + * Sorts the results in descending order by the given key. + * + * @method descending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'descending', + value: function () { + this._order = []; + + for (var _len3 = arguments.length, keys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + keys[_key3] = arguments[_key3]; + } + + return this.addDescending.apply(this, keys); + } + + /** + * Sorts the results in descending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addDescending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'addDescending', + value: function () { + var _this5 = this; + + if (!this._order) { + this._order = []; + } + + for (var _len4 = arguments.length, keys = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + keys[_key4] = arguments[_key4]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + key = key.join(); + } + _this5._order = _this5._order.concat(key.replace(/\s/g, '').split(',').map(function (k) { + return '-' + k; + })); + }); + + return this; + } + + /** Query Options **/ + + /** + * Sets the number of results to skip before returning any results. + * This is useful for pagination. + * Default is to skip zero results. + * @method skip + * @param {Number} n the number of results to skip. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'skip', + value: function (n) { + if (typeof n !== 'number' || n < 0) { + throw new Error('You can only skip by a positive number'); + } + this._skip = n; + return this; + } + + /** + * Sets the limit of the number of results to return. The default limit is + * 100, with a maximum of 1000 results being returned at a time. + * @method limit + * @param {Number} n the number of results to limit to. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'limit', + value: function (n) { + if (typeof n !== 'number') { + throw new Error('You can only set the limit to a numeric value'); + } + this._limit = n; + return this; + } + + /** + * Includes nested Parse.Objects for the provided key. You can use dot + * notation to specify which fields in the included object are also fetched. + * @method include + * @param {String} key The name of the key to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'include', + value: function () { + var _this6 = this; + + for (var _len5 = arguments.length, keys = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + keys[_key5] = arguments[_key5]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + _this6._include = _this6._include.concat(key); + } else { + _this6._include.push(key); + } + }); + return this; + } + + /** + * Restricts the fields of the returned Parse.Objects to include only the + * provided keys. If this is called multiple times, then all of the keys + * specified in each of the calls will be included. + * @method select + * @param {Array} keys The names of the keys to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'select', + value: function () { + var _this7 = this; + + if (!this._select) { + this._select = []; + } + + for (var _len6 = arguments.length, keys = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + keys[_key6] = arguments[_key6]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + _this7._select = _this7._select.concat(key); + } else { + _this7._select.push(key); + } + }); + return this; + } + + /** + * Subscribe this query to get liveQuery updates + * @method subscribe + * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter + * which can be used to get liveQuery updates. + */ + + }, { + key: 'subscribe', + value: function () { + var controller = _CoreManager2.default.getLiveQueryController(); + return controller.subscribe(this); + } + + /** + * Constructs a Parse.Query that is the OR of the passed in queries. For + * example: + *
      var compoundQuery = Parse.Query.or(query1, query2, query3);
      + * + * will create a compoundQuery that is an or of the query1, query2, and + * query3. + * @method or + * @param {...Parse.Query} var_args The list of queries to OR. + * @static + * @return {Parse.Query} The query that is the OR of the passed in queries. + */ + + }], [{ + key: 'or', + value: function () { + var className = null; + + for (var _len7 = arguments.length, queries = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + queries[_key7] = arguments[_key7]; + } + + queries.forEach(function (q) { + if (!className) { + className = q.className; + } + + if (className !== q.className) { + throw new Error('All queries must be for the same class.'); + } + }); + + var query = new ParseQuery(className); + query._orQuery(queries); + return query; + } + }]); + return ParseQuery; +}(); + +exports.default = ParseQuery; + +var DefaultController = { + find: function (className, params, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + return RESTController.request('GET', 'classes/' + className, params, options); + } +}; + +_CoreManager2.default.setQueryController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseRelation.js b/lib/browser/ParseRelation.js new file mode 100644 index 000000000..fe9ea8769 --- /dev/null +++ b/lib/browser/ParseRelation.js @@ -0,0 +1,182 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParseOp = require('./ParseOp'); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseQuery = require('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new Relation for the given parent object and key. This + * constructor should rarely be used directly, but rather created by + * Parse.Object.relation. + * @class Parse.Relation + * @constructor + * @param {Parse.Object} parent The parent of this relation. + * @param {String} key The key for this relation on the parent. + * + *

      + * A class that is used to access all of the children of a many-to-many + * relationship. Each instance of Parse.Relation is associated with a + * particular parent object and key. + *

      + */ +var ParseRelation = function () { + function ParseRelation(parent, key) { + (0, _classCallCheck3.default)(this, ParseRelation); + + this.parent = parent; + this.key = key; + this.targetClassName = null; + } + + /** + * Makes sure that this relation has the right parent and key. + */ + + (0, _createClass3.default)(ParseRelation, [{ + key: '_ensureParentAndKey', + value: function (parent, key) { + this.key = this.key || key; + if (this.key !== key) { + throw new Error('Internal Error. Relation retrieved from two different keys.'); + } + if (this.parent) { + if (this.parent.className !== parent.className) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + if (this.parent.id) { + if (this.parent.id !== parent.id) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + } else if (parent.id) { + this.parent = parent; + } + } else { + this.parent = parent; + } + } + + /** + * Adds a Parse.Object or an array of Parse.Objects to the relation. + * @method add + * @param {} objects The item or items to add. + */ + + }, { + key: 'add', + value: function (objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new _ParseOp.RelationOp(objects, []); + var parent = this.parent; + if (!parent) { + throw new Error('Cannot add to a Relation without a parent'); + } + parent.set(this.key, change); + this.targetClassName = change._targetClassName; + return parent; + } + + /** + * Removes a Parse.Object or an array of Parse.Objects from this relation. + * @method remove + * @param {} objects The item or items to remove. + */ + + }, { + key: 'remove', + value: function (objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new _ParseOp.RelationOp([], objects); + if (!this.parent) { + throw new Error('Cannot remove from a Relation without a parent'); + } + this.parent.set(this.key, change); + this.targetClassName = change._targetClassName; + } + + /** + * Returns a JSON version of the object suitable for saving to disk. + * @method toJSON + * @return {Object} + */ + + }, { + key: 'toJSON', + value: function () { + return { + __type: 'Relation', + className: this.targetClassName + }; + } + + /** + * Returns a Parse.Query that is limited to objects in this + * relation. + * @method query + * @return {Parse.Query} + */ + + }, { + key: 'query', + value: function () { + var query; + var parent = this.parent; + if (!parent) { + throw new Error('Cannot construct a query for a Relation without a parent'); + } + if (!this.targetClassName) { + query = new _ParseQuery2.default(parent.className); + query._extraOptions.redirectClassNameForKey = this.key; + } else { + query = new _ParseQuery2.default(this.targetClassName); + } + query._addCondition('$relatedTo', 'object', { + __type: 'Pointer', + className: parent.className, + objectId: parent.id + }); + query._addCondition('$relatedTo', 'key', this.key); + + return query; + } + }]); + return ParseRelation; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseRelation; \ No newline at end of file diff --git a/lib/browser/ParseRole.js b/lib/browser/ParseRole.js new file mode 100644 index 000000000..567af7a54 --- /dev/null +++ b/lib/browser/ParseRole.js @@ -0,0 +1,196 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _get2 = require('babel-runtime/helpers/get'); + +var _get3 = _interopRequireDefault(_get2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Represents a Role on the Parse server. Roles represent groupings of + * Users for the purposes of granting permissions (e.g. specifying an ACL + * for an Object). Roles are specified by their sets of child users and + * child roles, all of which are granted any permissions that the parent + * role has. + * + *

      Roles must have a name (which cannot be changed after creation of the + * role), and must specify an ACL.

      + * @class Parse.Role + * @constructor + * @param {String} name The name of the Role to create. + * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. + * A Parse.Role is a local representation of a role persisted to the Parse + * cloud. + */ +var ParseRole = function (_ParseObject) { + (0, _inherits3.default)(ParseRole, _ParseObject); + + function ParseRole(name, acl) { + (0, _classCallCheck3.default)(this, ParseRole); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseRole.__proto__ || (0, _getPrototypeOf2.default)(ParseRole)).call(this, '_Role')); + + if (typeof name === 'string' && acl instanceof _ParseACL2.default) { + _this.setName(name); + _this.setACL(acl); + } + return _this; + } + + /** + * Gets the name of the role. You can alternatively call role.get("name") + * + * @method getName + * @return {String} the name of the role. + */ + + (0, _createClass3.default)(ParseRole, [{ + key: 'getName', + value: function () { + var name = this.get('name'); + if (name == null || typeof name === 'string') { + return name; + } + return ''; + } + + /** + * Sets the name for a role. This value must be set before the role has + * been saved to the server, and cannot be set once the role has been + * saved. + * + *

      + * A role's name can only contain alphanumeric characters, _, -, and + * spaces. + *

      + * + *

      This is equivalent to calling role.set("name", name)

      + * + * @method setName + * @param {String} name The name of the role. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + + }, { + key: 'setName', + value: function (name, options) { + return this.set('name', name, options); + } + + /** + * Gets the Parse.Relation for the Parse.Users that are direct + * children of this role. These users are granted any privileges that this + * role has been granted (e.g. read or write access through ACLs). You can + * add or remove users from the role through this relation. + * + *

      This is equivalent to calling role.relation("users")

      + * + * @method getUsers + * @return {Parse.Relation} the relation for the users belonging to this + * role. + */ + + }, { + key: 'getUsers', + value: function () { + return this.relation('users'); + } + + /** + * Gets the Parse.Relation for the Parse.Roles that are direct + * children of this role. These roles' users are granted any privileges that + * this role has been granted (e.g. read or write access through ACLs). You + * can add or remove child roles from this role through this relation. + * + *

      This is equivalent to calling role.relation("roles")

      + * + * @method getRoles + * @return {Parse.Relation} the relation for the roles belonging to this + * role. + */ + + }, { + key: 'getRoles', + value: function () { + return this.relation('roles'); + } + }, { + key: 'validate', + value: function (attrs, options) { + var isInvalid = (0, _get3.default)(ParseRole.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseRole.prototype), 'validate', this).call(this, attrs, options); + if (isInvalid) { + return isInvalid; + } + + if ('name' in attrs && attrs.name !== this.getName()) { + var newName = attrs.name; + if (this.id && this.id !== attrs.objectId) { + // Check to see if the objectId being set matches this.id + // This happens during a fetch -- the id is set before calling fetch + // Let the name be set in this case + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); + } + if (typeof newName !== 'string') { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name must be a String.'); + } + if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); + } + } + return false; + } + }]); + return ParseRole; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseRole; + +_ParseObject3.default.registerSubclass('_Role', ParseRole); \ No newline at end of file diff --git a/lib/browser/ParseSession.js b/lib/browser/ParseSession.js new file mode 100644 index 000000000..7fb75c80d --- /dev/null +++ b/lib/browser/ParseSession.js @@ -0,0 +1,180 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _isRevocableSession = require('./isRevocableSession'); + +var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseUser = require('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * @class Parse.Session + * @constructor + * + *

      A Parse.Session object is a local representation of a revocable session. + * This class is a subclass of a Parse.Object, and retains the same + * functionality of a Parse.Object.

      + */ +var ParseSession = function (_ParseObject) { + (0, _inherits3.default)(ParseSession, _ParseObject); + + function ParseSession(attributes) { + (0, _classCallCheck3.default)(this, ParseSession); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseSession.__proto__ || (0, _getPrototypeOf2.default)(ParseSession)).call(this, '_Session')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + return _this; + } + + /** + * Returns the session token string. + * @method getSessionToken + * @return {String} + */ + + (0, _createClass3.default)(ParseSession, [{ + key: 'getSessionToken', + value: function () { + var token = this.get('sessionToken'); + if (typeof token === 'string') { + return token; + } + return ''; + } + }], [{ + key: 'readOnlyAttributes', + value: function () { + return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; + } + + /** + * Retrieves the Session object for the currently logged in session. + * @method current + * @static + * @return {Parse.Promise} A promise that is resolved with the Parse.Session + * object after it has been fetched. If there is no current user, the + * promise will be rejected. + */ + + }, { + key: 'current', + value: function (options) { + options = options || {}; + var controller = _CoreManager2.default.getSessionController(); + + var sessionOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + sessionOptions.useMasterKey = options.useMasterKey; + } + return _ParseUser2.default.currentAsync().then(function (user) { + if (!user) { + return _ParsePromise2.default.error('There is no current user.'); + } + user.getSessionToken(); + + sessionOptions.sessionToken = user.getSessionToken(); + return controller.getSession(sessionOptions); + }); + } + + /** + * Determines whether the current session token is revocable. + * This method is useful for migrating Express.js or Node.js web apps to + * use revocable sessions. If you are migrating an app that uses the Parse + * SDK in the browser only, please use Parse.User.enableRevocableSession() + * instead, so that sessions can be automatically upgraded. + * @method isCurrentSessionRevocable + * @static + * @return {Boolean} + */ + + }, { + key: 'isCurrentSessionRevocable', + value: function () { + var currentUser = _ParseUser2.default.current(); + if (currentUser) { + return (0, _isRevocableSession2.default)(currentUser.getSessionToken() || ''); + } + return false; + } + }]); + return ParseSession; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseSession; + +_ParseObject3.default.registerSubclass('_Session', ParseSession); + +var DefaultController = { + getSession: function (options) { + var RESTController = _CoreManager2.default.getRESTController(); + var session = new ParseSession(); + + return RESTController.request('GET', 'sessions/me', {}, options).then(function (sessionData) { + session._finishFetch(sessionData); + session._setExisted(true); + return session; + }); + } +}; + +_CoreManager2.default.setSessionController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseUser.js b/lib/browser/ParseUser.js new file mode 100644 index 000000000..f18f42820 --- /dev/null +++ b/lib/browser/ParseUser.js @@ -0,0 +1,1150 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _defineProperty = require('babel-runtime/core-js/object/define-property'); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _get2 = require('babel-runtime/helpers/get'); + +var _get3 = _interopRequireDefault(_get2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _isRevocableSession = require('./isRevocableSession'); + +var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseSession = require('./ParseSession'); + +var _ParseSession2 = _interopRequireDefault(_ParseSession); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var CURRENT_USER_KEY = 'currentUser'; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var canUseCurrentUser = !_CoreManager2.default.get('IS_NODE'); +var currentUserCacheMatchesDisk = false; +var currentUserCache = null; + +var authProviders = {}; + +/** + * @class Parse.User + * @constructor + * + *

      A Parse.User object is a local representation of a user persisted to the + * Parse cloud. This class is a subclass of a Parse.Object, and retains the + * same functionality of a Parse.Object, but also extends it with various + * user specific methods, like authentication, signing up, and validation of + * uniqueness.

      + */ + +var ParseUser = function (_ParseObject) { + (0, _inherits3.default)(ParseUser, _ParseObject); + + function ParseUser(attributes) { + (0, _classCallCheck3.default)(this, ParseUser); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseUser.__proto__ || (0, _getPrototypeOf2.default)(ParseUser)).call(this, '_User')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Parse User'); + } + } + return _this; + } + + /** + * Request a revocable session token to replace the older style of token. + * @method _upgradeToRevocableSession + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is resolved when the replacement + * token has been fetched. + */ + + (0, _createClass3.default)(ParseUser, [{ + key: '_upgradeToRevocableSession', + value: function (options) { + options = options || {}; + + var upgradeOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + upgradeOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); + } + + /** + * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can + * call linkWith on the user (even if it doesn't exist yet on the server). + * @method _linkWith + */ + + }, { + key: '_linkWith', + value: function (provider, options) { + var _this2 = this; + + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[provider]; + } else { + authType = provider.getAuthType(); + } + if (options && options.hasOwnProperty('authData')) { + var authData = this.get('authData') || {}; + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + throw new Error('Invalid type: authData field should be an object'); + } + authData[authType] = options.authData; + + var controller = _CoreManager2.default.getUserController(); + return controller.linkWith(this, authData)._thenRunCallbacks(options, this); + } else { + var promise = new _ParsePromise2.default(); + provider.authenticate({ + success: function (provider, result) { + var opts = {}; + opts.authData = result; + if (options.success) { + opts.success = options.success; + } + if (options.error) { + opts.error = options.error; + } + _this2._linkWith(provider, opts).then(function () { + promise.resolve(_this2); + }, function (error) { + promise.reject(error); + }); + }, + error: function (provider, _error) { + if (typeof options.error === 'function') { + options.error(_this2, _error); + } + promise.reject(_error); + } + }); + return promise; + } + } + + /** + * Synchronizes auth data for a provider (e.g. puts the access token in the + * right place to be used by the Facebook SDK). + * @method _synchronizeAuthData + */ + + }, { + key: '_synchronizeAuthData', + value: function (provider) { + if (!this.isCurrent() || !provider) { + return; + } + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[authType]; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData'); + if (!provider || !authData || (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + var success = provider.restoreAuthentication(authData[authType]); + if (!success) { + this._unlinkFrom(provider); + } + } + + /** + * Synchronizes authData for all providers. + * @method _synchronizeAllAuthData + */ + + }, { + key: '_synchronizeAllAuthData', + value: function () { + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + this._synchronizeAuthData(key); + } + } + + /** + * Removes null values from authData (which exist temporarily for + * unlinking) + * @method _cleanupAuthData + */ + + }, { + key: '_cleanupAuthData', + value: function () { + if (!this.isCurrent()) { + return; + } + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + if (!authData[key]) { + delete authData[key]; + } + } + } + + /** + * Unlinks a user from a service. + * @method _unlinkFrom + */ + + }, { + key: '_unlinkFrom', + value: function (provider, options) { + var _this3 = this; + + if (typeof provider === 'string') { + provider = authProviders[provider]; + } else { + provider.getAuthType(); + } + return this._linkWith(provider, { authData: null }).then(function () { + _this3._synchronizeAuthData(provider); + return _ParsePromise2.default.as(_this3); + })._thenRunCallbacks(options); + } + + /** + * Checks whether a user is linked to a service. + * @method _isLinked + */ + + }, { + key: '_isLinked', + value: function (provider) { + var authType; + if (typeof provider === 'string') { + authType = provider; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData') || {}; + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return false; + } + return !!authData[authType]; + } + + /** + * Deauthenticates all providers. + * @method _logOutWithAll + */ + + }, { + key: '_logOutWithAll', + value: function () { + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + this._logOutWith(key); + } + } + + /** + * Deauthenticates a single provider (e.g. removing access tokens from the + * Facebook SDK). + * @method _logOutWith + */ + + }, { + key: '_logOutWith', + value: function (provider) { + if (!this.isCurrent()) { + return; + } + if (typeof provider === 'string') { + provider = authProviders[provider]; + } + if (provider && provider.deauthenticate) { + provider.deauthenticate(); + } + } + + /** + * Class instance method used to maintain specific keys when a fetch occurs. + * Used to ensure that the session token is not lost. + */ + + }, { + key: '_preserveFieldsOnFetch', + value: function () { + return { + sessionToken: this.get('sessionToken') + }; + } + + /** + * Returns true if current would return this user. + * @method isCurrent + * @return {Boolean} + */ + + }, { + key: 'isCurrent', + value: function () { + var current = ParseUser.current(); + return !!current && current.id === this.id; + } + + /** + * Returns get("username"). + * @method getUsername + * @return {String} + */ + + }, { + key: 'getUsername', + value: function () { + var username = this.get('username'); + if (username == null || typeof username === 'string') { + return username; + } + return ''; + } + + /** + * Calls set("username", username, options) and returns the result. + * @method setUsername + * @param {String} username + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setUsername', + value: function (username) { + // Strip anonymity, even we do not support anonymous user in js SDK, we may + // encounter anonymous user created by android/iOS in cloud code. + var authData = this.get('authData'); + if (authData && (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) === 'object' && authData.hasOwnProperty('anonymous')) { + // We need to set anonymous to null instead of deleting it in order to remove it from Parse. + authData.anonymous = null; + } + this.set('username', username); + } + + /** + * Calls set("password", password, options) and returns the result. + * @method setPassword + * @param {String} password + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setPassword', + value: function (password) { + this.set('password', password); + } + + /** + * Returns get("email"). + * @method getEmail + * @return {String} + */ + + }, { + key: 'getEmail', + value: function () { + var email = this.get('email'); + if (email == null || typeof email === 'string') { + return email; + } + return ''; + } + + /** + * Calls set("email", email, options) and returns the result. + * @method setEmail + * @param {String} email + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setEmail', + value: function (email) { + this.set('email', email); + } + + /** + * Returns the session token for this user, if the user has been logged in, + * or if it is the result of a query with the master key. Otherwise, returns + * undefined. + * @method getSessionToken + * @return {String} the session token, or undefined + */ + + }, { + key: 'getSessionToken', + value: function () { + var token = this.get('sessionToken'); + if (token == null || typeof token === 'string') { + return token; + } + return ''; + } + + /** + * Checks whether this user is the current user and has been authenticated. + * @method authenticated + * @return (Boolean) whether this user is the current user and is logged in. + */ + + }, { + key: 'authenticated', + value: function () { + var current = ParseUser.current(); + return !!this.get('sessionToken') && !!current && current.id === this.id; + } + + /** + * Signs up a new user. You should call this instead of save for + * new Parse.Users. This will create a new Parse.User on the server, and + * also persist the session on disk so that you can access the user using + * current. + * + *

      A username and password must be set before calling signUp.

      + * + *

      Calls options.success or options.error on completion.

      + * + * @method signUp + * @param {Object} attrs Extra fields to set on the new user, or null. + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled when the signup + * finishes. + */ + + }, { + key: 'signUp', + value: function (attrs, options) { + options = options || {}; + + var signupOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + signupOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + signupOptions.installationId = options.installationId; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); + } + + /** + * Logs in a Parse.User. On success, this saves the session to disk, + * so you can retrieve the currently logged in user using + * current. + * + *

      A username and password must be set before calling logIn.

      + * + *

      Calls options.success or options.error on completion.

      + * + * @method logIn + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login is complete. + */ + + }, { + key: 'logIn', + value: function (options) { + options = options || {}; + + var loginOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + loginOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + loginOptions.installationId = options.installationId; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); + } + + /** + * Wrap the default save behavior with functionality to save to local + * storage if this is current user. + */ + + }, { + key: 'save', + value: function () { + var _this4 = this; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'save', this).apply(this, args).then(function () { + if (_this4.isCurrent()) { + return _CoreManager2.default.getUserController().updateUserOnDisk(_this4); + } + return _this4; + }); + } + + /** + * Wrap the default destroy behavior with functionality that logs out + * the current user when it is destroyed + */ + + }, { + key: 'destroy', + value: function () { + var _this5 = this; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'destroy', this).apply(this, args).then(function () { + if (_this5.isCurrent()) { + return _CoreManager2.default.getUserController().removeUserFromDisk(); + } + return _this5; + }); + } + + /** + * Wrap the default fetch behavior with functionality to save to local + * storage if this is current user. + */ + + }, { + key: 'fetch', + value: function () { + var _this6 = this; + + for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'fetch', this).apply(this, args).then(function () { + if (_this6.isCurrent()) { + return _CoreManager2.default.getUserController().updateUserOnDisk(_this6); + } + return _this6; + }); + } + }], [{ + key: 'readOnlyAttributes', + value: function () { + return ['sessionToken']; + } + + /** + * Adds functionality to the existing Parse.User class + * @method extend + * @param {Object} protoProps A set of properties to add to the prototype + * @param {Object} classProps A set of static properties to add to the class + * @static + * @return {Class} The newly extended Parse.User class + */ + + }, { + key: 'extend', + value: function (protoProps, classProps) { + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseUser.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseUser, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + return ParseUser; + } + + /** + * Retrieves the currently logged in ParseUser with a valid session, + * either from memory or localStorage, if necessary. + * @method current + * @static + * @return {Parse.Object} The currently logged in Parse.User. + */ + + }, { + key: 'current', + value: function () { + if (!canUseCurrentUser) { + return null; + } + var controller = _CoreManager2.default.getUserController(); + return controller.currentUser(); + } + + /** + * Retrieves the currently logged in ParseUser from asynchronous Storage. + * @method currentAsync + * @static + * @return {Parse.Promise} A Promise that is resolved with the currently + * logged in Parse User + */ + + }, { + key: 'currentAsync', + value: function () { + if (!canUseCurrentUser) { + return _ParsePromise2.default.as(null); + } + var controller = _CoreManager2.default.getUserController(); + return controller.currentUserAsync(); + } + + /** + * Signs up a new user with a username (or email) and password. + * This will create a new Parse.User on the server, and also persist the + * session in localStorage so that you can access the user using + * {@link #current}. + * + *

      Calls options.success or options.error on completion.

      + * + * @method signUp + * @param {String} username The username (or email) to sign up with. + * @param {String} password The password to sign up with. + * @param {Object} attrs Extra fields to set on the new user. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the signup completes. + */ + + }, { + key: 'signUp', + value: function (username, password, attrs, options) { + attrs = attrs || {}; + attrs.username = username; + attrs.password = password; + var user = new ParseUser(attrs); + return user.signUp({}, options); + } + + /** + * Logs in a user with a username (or email) and password. On success, this + * saves the session to disk, so you can retrieve the currently logged in + * user using current. + * + *

      Calls options.success or options.error on completion.

      + * + * @method logIn + * @param {String} username The username (or email) to log in with. + * @param {String} password The password to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + + }, { + key: 'logIn', + value: function (username, password, options) { + if (typeof username !== 'string') { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Username must be a string.')); + } else if (typeof password !== 'string') { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Password must be a string.')); + } + var user = new ParseUser(); + user._finishFetch({ username: username, password: password }); + return user.logIn(options); + } + + /** + * Logs in a user with a session token. On success, this saves the session + * to disk, so you can retrieve the currently logged in user using + * current. + * + *

      Calls options.success or options.error on completion.

      + * + * @method become + * @param {String} sessionToken The sessionToken to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + + }, { + key: 'become', + value: function (sessionToken, options) { + if (!canUseCurrentUser) { + throw new Error('It is not memory-safe to become a user in a server environment'); + } + options = options || {}; + + var becomeOptions = { + sessionToken: sessionToken + }; + if (options.hasOwnProperty('useMasterKey')) { + becomeOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.become(becomeOptions)._thenRunCallbacks(options); + } + }, { + key: 'logInWith', + value: function (provider, options) { + return ParseUser._logInWith(provider, options); + } + + /** + * Logs out the currently logged in user session. This will remove the + * session from disk, log out of linked services, and future calls to + * current will return null. + * @method logOut + * @static + * @return {Parse.Promise} A promise that is resolved when the session is + * destroyed on the server. + */ + + }, { + key: 'logOut', + value: function () { + if (!canUseCurrentUser) { + throw new Error('There is no current user user on a node.js server environment.'); + } + + var controller = _CoreManager2.default.getUserController(); + return controller.logOut(); + } + + /** + * Requests a password reset email to be sent to the specified email address + * associated with the user account. This email allows the user to securely + * reset their password on the Parse site. + * + *

      Calls options.success or options.error on completion.

      + * + * @method requestPasswordReset + * @param {String} email The email address associated with the user that + * forgot their password. + * @param {Object} options A Backbone-style options object. + * @static + */ + + }, { + key: 'requestPasswordReset', + value: function (email, options) { + options = options || {}; + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); + } + + /** + * Allow someone to define a custom User class without className + * being rewritten to _User. The default behavior is to rewrite + * User to _User for legacy reasons. This allows developers to + * override that behavior. + * + * @method allowCustomUserClass + * @param {Boolean} isAllowed Whether or not to allow custom User class + * @static + */ + + }, { + key: 'allowCustomUserClass', + value: function (isAllowed) { + _CoreManager2.default.set('PERFORM_USER_REWRITE', !isAllowed); + } + + /** + * Allows a legacy application to start using revocable sessions. If the + * current session token is not revocable, a request will be made for a new, + * revocable session. + * It is not necessary to call this method from cloud code unless you are + * handling user signup or login from the server side. In a cloud code call, + * this function will not attempt to upgrade the current token. + * @method enableRevocableSession + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is resolved when the process has + * completed. If a replacement session token is requested, the promise + * will be resolved after a new token has been fetched. + */ + + }, { + key: 'enableRevocableSession', + value: function (options) { + options = options || {}; + _CoreManager2.default.set('FORCE_REVOCABLE_SESSION', true); + if (canUseCurrentUser) { + var current = ParseUser.current(); + if (current) { + return current._upgradeToRevocableSession(options); + } + } + return _ParsePromise2.default.as()._thenRunCallbacks(options); + } + + /** + * Enables the use of become or the current user in a server + * environment. These features are disabled by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method enableUnsafeCurrentUser + * @static + */ + + }, { + key: 'enableUnsafeCurrentUser', + value: function () { + canUseCurrentUser = true; + } + + /** + * Disables the use of become or the current user in any environment. + * These features are disabled on servers by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method disableUnsafeCurrentUser + * @static + */ + + }, { + key: 'disableUnsafeCurrentUser', + value: function () { + canUseCurrentUser = false; + } + }, { + key: '_registerAuthenticationProvider', + value: function (provider) { + authProviders[provider.getAuthType()] = provider; + // Synchronize the current user with the auth provider. + ParseUser.currentAsync().then(function (current) { + if (current) { + current._synchronizeAuthData(provider.getAuthType()); + } + }); + } + }, { + key: '_logInWith', + value: function (provider, options) { + var user = new ParseUser(); + return user._linkWith(provider, options); + } + }, { + key: '_clearCache', + value: function () { + currentUserCache = null; + currentUserCacheMatchesDisk = false; + } + }, { + key: '_setCurrentUserCache', + value: function (user) { + currentUserCache = user; + } + }]); + return ParseUser; +}(_ParseObject3.default); + +exports.default = ParseUser; + +_ParseObject3.default.registerSubclass('_User', ParseUser); + +var DefaultController = { + updateUserOnDisk: function (user) { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var json = user.toJSON(); + json.className = '_User'; + return _Storage2.default.setItemAsync(path, (0, _stringify2.default)(json)).then(function () { + return user; + }); + }, + removeUserFromDisk: function () { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + currentUserCacheMatchesDisk = true; + currentUserCache = null; + return _Storage2.default.removeItemAsync(path); + }, + setCurrentUser: function (user) { + currentUserCache = user; + user._cleanupAuthData(); + user._synchronizeAllAuthData(); + return DefaultController.updateUserOnDisk(user); + }, + currentUser: function () { + if (currentUserCache) { + return currentUserCache; + } + if (currentUserCacheMatchesDisk) { + return null; + } + if (_Storage2.default.async()) { + throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); + } + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var userData = _Storage2.default.getItem(path); + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return null; + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = _ParseObject3.default.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return current; + }, + currentUserAsync: function () { + if (currentUserCache) { + return _ParsePromise2.default.as(currentUserCache); + } + if (currentUserCacheMatchesDisk) { + return _ParsePromise2.default.as(null); + } + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + return _Storage2.default.getItemAsync(path).then(function (userData) { + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return _ParsePromise2.default.as(null); + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = _ParseObject3.default.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return _ParsePromise2.default.as(current); + }); + }, + signUp: function (user, attrs, options) { + var username = attrs && attrs.username || user.get('username'); + var password = attrs && attrs.password || user.get('password'); + + if (!username || !username.length) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); + } + if (!password || !password.length) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); + } + + return user.save(attrs, options).then(function () { + // Clear the password field + user._finishFetch({ password: undefined }); + + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + }, + logIn: function (user, options) { + var RESTController = _CoreManager2.default.getRESTController(); + var stateController = _CoreManager2.default.getObjectStateController(); + var auth = { + username: user.get('username'), + password: user.get('password') + }; + return RESTController.request('GET', 'login', auth, options).then(function (response, status) { + user._migrateId(response.objectId); + user._setExisted(true); + stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); + stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); + response.password = undefined; + user._finishFetch(response); + if (!canUseCurrentUser) { + // We can't set the current user, so just return the one we logged in + return _ParsePromise2.default.as(user); + } + return DefaultController.setCurrentUser(user); + }); + }, + become: function (options) { + var user = new ParseUser(); + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('GET', 'users/me', {}, options).then(function (response, status) { + user._finishFetch(response); + user._setExisted(true); + return DefaultController.setCurrentUser(user); + }); + }, + logOut: function () { + return DefaultController.currentUserAsync().then(function (currentUser) { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var promise = _Storage2.default.removeItemAsync(path); + var RESTController = _CoreManager2.default.getRESTController(); + if (currentUser !== null) { + var currentSession = currentUser.getSessionToken(); + if (currentSession && (0, _isRevocableSession2.default)(currentSession)) { + promise = promise.then(function () { + return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); + }); + } + currentUser._logOutWithAll(); + currentUser._finishFetch({ sessionToken: undefined }); + } + currentUserCacheMatchesDisk = true; + currentUserCache = null; + + return promise; + }); + }, + requestPasswordReset: function (email, options) { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); + }, + upgradeToRevocableSession: function (user, options) { + var token = user.getSessionToken(); + if (!token) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.SESSION_MISSING, 'Cannot upgrade a user with no session token')); + } + + options.sessionToken = token; + + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(function (result) { + var session = new _ParseSession2.default(); + session._finishFetch(result); + user._finishFetch({ sessionToken: session.getSessionToken() }); + if (user.isCurrent()) { + return DefaultController.setCurrentUser(user); + } + return _ParsePromise2.default.as(user); + }); + }, + linkWith: function (user, authData) { + return user.save({ authData: authData }).then(function () { + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + } +}; + +_CoreManager2.default.setUserController(DefaultController); \ No newline at end of file diff --git a/lib/browser/Push.js b/lib/browser/Push.js new file mode 100644 index 000000000..cfb740767 --- /dev/null +++ b/lib/browser/Push.js @@ -0,0 +1,98 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.send = send; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParseQuery = require('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains functions to deal with Push in Parse. + * @class Parse.Push + * @static + */ + +/** + * Sends a push notification. + * @method send + * @param {Object} data - The data of the push notification. Valid fields + * are: + *
        + *
      1. channels - An Array of channels to push to.
      2. + *
      3. push_time - A Date object for when to send the push.
      4. + *
      5. expiration_time - A Date object for when to expire + * the push.
      6. + *
      7. expiration_interval - The seconds from now to expire the push.
      8. + *
      9. where - A Parse.Query over Parse.Installation that is used to match + * a set of installations to push to.
      10. + *
      11. data - The data to send as part of the push
      12. + *
          + * @param {Object} options An object that has an optional success function, + * that takes no arguments and will be called on a successful push, and + * an error function that takes a Parse.Error and will be called if the push + * failed. + * @return {Parse.Promise} A promise that is fulfilled when the push request + * completes. + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function send(data, options) { + options = options || {}; + + if (data.where && data.where instanceof _ParseQuery2.default) { + data.where = data.where.toJSON().where; + } + + if (data.push_time && (0, _typeof3.default)(data.push_time) === 'object') { + data.push_time = data.push_time.toJSON(); + } + + if (data.expiration_time && (0, _typeof3.default)(data.expiration_time) === 'object') { + data.expiration_time = data.expiration_time.toJSON(); + } + + if (data.expiration_time && data.expiration_interval) { + throw new Error('expiration_time and expiration_interval cannot both be set.'); + } + + return _CoreManager2.default.getPushController().send(data, { + useMasterKey: options.useMasterKey + })._thenRunCallbacks(options); +} + +var DefaultController = { + send: function (data, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); + + return request._thenRunCallbacks(options); + } +}; + +_CoreManager2.default.setPushController(DefaultController); \ No newline at end of file diff --git a/lib/browser/RESTController.js b/lib/browser/RESTController.js new file mode 100644 index 000000000..f8ea70e2f --- /dev/null +++ b/lib/browser/RESTController.js @@ -0,0 +1,248 @@ +'use strict'; + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var XHR = null; +if (typeof XMLHttpRequest !== 'undefined') { + XHR = XMLHttpRequest; +} + + +var useXDomainRequest = false; +if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { + useXDomainRequest = true; +} + +function ajaxIE9(method, url, data) { + var promise = new _ParsePromise2.default(); + var xdr = new XDomainRequest(); + xdr.onload = function () { + var response; + try { + response = JSON.parse(xdr.responseText); + } catch (e) { + promise.reject(e); + } + if (response) { + promise.resolve(response); + } + }; + xdr.onerror = xdr.ontimeout = function () { + // Let's fake a real error message. + var fakeResponse = { + responseText: (0, _stringify2.default)({ + code: _ParseError2.default.X_DOMAIN_REQUEST, + error: 'IE\'s XDomainRequest does not supply error info.' + }) + }; + promise.reject(fakeResponse); + }; + xdr.onprogress = function () {}; + xdr.open(method, url); + xdr.send(data); + return promise; +} + +var RESTController = { + ajax: function (method, url, data, headers) { + if (useXDomainRequest) { + return ajaxIE9(method, url, data, headers); + } + + var promise = new _ParsePromise2.default(); + var attempts = 0; + + (function dispatch() { + if (XHR == null) { + throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); + } + var handled = false; + var xhr = new XHR(); + + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4 || handled) { + return; + } + handled = true; + + if (xhr.status >= 200 && xhr.status < 300) { + var response; + try { + response = JSON.parse(xhr.responseText); + } catch (e) { + promise.reject(e.toString()); + } + if (response) { + promise.resolve(response, xhr.status, xhr); + } + } else if (xhr.status >= 500 || xhr.status === 0) { + // retry on 5XX or node-xmlhttprequest error + if (++attempts < _CoreManager2.default.get('REQUEST_ATTEMPT_LIMIT')) { + // Exponentially-growing random delay + var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); + setTimeout(dispatch, delay); + } else if (xhr.status === 0) { + promise.reject('Unable to connect to the Parse API'); + } else { + // After the retry limit is reached, fail + promise.reject(xhr); + } + } else { + promise.reject(xhr); + } + }; + + headers = headers || {}; + if (typeof headers['Content-Type'] !== 'string') { + headers['Content-Type'] = 'text/plain'; // Avoid pre-flight + } + if (_CoreManager2.default.get('IS_NODE')) { + headers['User-Agent'] = 'Parse/' + _CoreManager2.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; + } + + xhr.open(method, url, true); + for (var h in headers) { + xhr.setRequestHeader(h, headers[h]); + } + xhr.send(data); + })(); + + return promise; + }, + request: function (method, path, data, options) { + options = options || {}; + var url = _CoreManager2.default.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += path; + + var payload = {}; + if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') { + for (var k in data) { + payload[k] = data[k]; + } + } + + if (method !== 'POST') { + payload._method = method; + method = 'POST'; + } + + payload._ApplicationId = _CoreManager2.default.get('APPLICATION_ID'); + var jsKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); + if (jsKey) { + payload._JavaScriptKey = jsKey; + } + payload._ClientVersion = _CoreManager2.default.get('VERSION'); + + var useMasterKey = options.useMasterKey; + if (typeof useMasterKey === 'undefined') { + useMasterKey = _CoreManager2.default.get('USE_MASTER_KEY'); + } + if (useMasterKey) { + if (_CoreManager2.default.get('MASTER_KEY')) { + delete payload._JavaScriptKey; + payload._MasterKey = _CoreManager2.default.get('MASTER_KEY'); + } else { + throw new Error('Cannot use the Master Key, it has not been provided.'); + } + } + + if (_CoreManager2.default.get('FORCE_REVOCABLE_SESSION')) { + payload._RevocableSession = '1'; + } + + var installationId = options.installationId; + var installationIdPromise; + if (installationId && typeof installationId === 'string') { + installationIdPromise = _ParsePromise2.default.as(installationId); + } else { + var installationController = _CoreManager2.default.getInstallationController(); + installationIdPromise = installationController.currentInstallationId(); + } + + return installationIdPromise.then(function (iid) { + payload._InstallationId = iid; + var userController = _CoreManager2.default.getUserController(); + if (options && typeof options.sessionToken === 'string') { + return _ParsePromise2.default.as(options.sessionToken); + } else if (userController) { + return userController.currentUserAsync().then(function (user) { + if (user) { + return _ParsePromise2.default.as(user.getSessionToken()); + } + return _ParsePromise2.default.as(null); + }); + } + return _ParsePromise2.default.as(null); + }).then(function (token) { + if (token) { + payload._SessionToken = token; + } + + var payloadString = (0, _stringify2.default)(payload); + + return RESTController.ajax(method, url, payloadString); + }).then(null, function (response) { + // Transform the error into an instance of ParseError by trying to parse + // the error string as JSON + var error; + if (response && response.responseText) { + try { + var errorJSON = JSON.parse(response.responseText); + error = new _ParseError2.default(errorJSON.code, errorJSON.error); + } catch (e) { + // If we fail to parse the error text, that's okay. + error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); + } + } else { + error = new _ParseError2.default(_ParseError2.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify2.default)(response)); + } + + return _ParsePromise2.default.error(error); + }); + }, + _setXHR: function (xhr) { + XHR = xhr; + } +}; + +module.exports = RESTController; \ No newline at end of file diff --git a/lib/browser/SingleInstanceStateController.js b/lib/browser/SingleInstanceStateController.js new file mode 100644 index 000000000..545dd4c5d --- /dev/null +++ b/lib/browser/SingleInstanceStateController.js @@ -0,0 +1,160 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getState = getState; +exports.initializeState = initializeState; +exports.removeState = removeState; +exports.getServerData = getServerData; +exports.setServerData = setServerData; +exports.getPendingOps = getPendingOps; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.getObjectCache = getObjectCache; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; +exports.enqueueTask = enqueueTask; +exports.clearAllState = clearAllState; +exports.duplicateState = duplicateState; + +var _ObjectStateMutations = require('./ObjectStateMutations'); + +var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +var objectState = {}; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function getState(obj) { + var classData = objectState[obj.className]; + if (classData) { + return classData[obj.id] || null; + } + return null; +} + +function initializeState(obj, initial) { + var state = getState(obj); + if (state) { + return state; + } + if (!objectState[obj.className]) { + objectState[obj.className] = {}; + } + if (!initial) { + initial = ObjectStateMutations.defaultState(); + } + state = objectState[obj.className][obj.id] = initial; + return state; +} + +function removeState(obj) { + var state = getState(obj); + if (state === null) { + return null; + } + delete objectState[obj.className][obj.id]; + return state; +} + +function getServerData(obj) { + var state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +function setServerData(obj, attributes) { + var serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +function getPendingOps(obj) { + var state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +function setPendingOp(obj, attr, op) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +function pushPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +function popPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +function mergeFirstPendingState(obj) { + var pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +function getObjectCache(obj) { + var state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +function estimateAttribute(obj, attr) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +function estimateAttributes(obj) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +function commitServerChanges(obj, changes) { + var state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +function enqueueTask(obj, task) { + var state = initializeState(obj); + return state.tasks.enqueue(task); +} + +function clearAllState() { + objectState = {}; +} + +function duplicateState(source, dest) { + dest.id = source.id; +} \ No newline at end of file diff --git a/lib/browser/Storage.js b/lib/browser/Storage.js new file mode 100644 index 000000000..e5260e608 --- /dev/null +++ b/lib/browser/Storage.js @@ -0,0 +1,93 @@ +'use strict'; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = { + async: function () { + var controller = _CoreManager2.default.getStorageController(); + return !!controller.async; + }, + getItem: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.getItem(path); + }, + getItemAsync: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.getItemAsync(path); + } + return _ParsePromise2.default.as(controller.getItem(path)); + }, + setItem: function (path, value) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.setItem(path, value); + }, + setItemAsync: function (path, value) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.setItemAsync(path, value); + } + return _ParsePromise2.default.as(controller.setItem(path, value)); + }, + removeItem: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.removeItem(path); + }, + removeItemAsync: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.removeItemAsync(path); + } + return _ParsePromise2.default.as(controller.removeItem(path)); + }, + generatePath: function (path) { + if (!_CoreManager2.default.get('APPLICATION_ID')) { + throw new Error('You need to call Parse.initialize before using Parse.'); + } + if (typeof path !== 'string') { + throw new Error('Tried to get a Storage path that was not a String.'); + } + if (path[0] === '/') { + path = path.substr(1); + } + return 'Parse/' + _CoreManager2.default.get('APPLICATION_ID') + '/' + path; + }, + _clear: function () { + var controller = _CoreManager2.default.getStorageController(); + if (controller.hasOwnProperty('clear')) { + controller.clear(); + } + } +}; + +_CoreManager2.default.setStorageController(require('./StorageController.browser')); \ No newline at end of file diff --git a/lib/browser/StorageController.browser.js b/lib/browser/StorageController.browser.js new file mode 100644 index 000000000..d372924a0 --- /dev/null +++ b/lib/browser/StorageController.browser.js @@ -0,0 +1,41 @@ +'use strict'; + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var StorageController = { + async: 0, + + getItem: function (path) { + return localStorage.getItem(path); + }, + setItem: function (path, value) { + try { + localStorage.setItem(path, value); + } catch (e) { + // Quota exceeded, possibly due to Safari Private Browsing mode + } + }, + removeItem: function (path) { + localStorage.removeItem(path); + }, + clear: function () { + localStorage.clear(); + } +}; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/browser/StorageController.default.js b/lib/browser/StorageController.default.js new file mode 100644 index 000000000..460c1e2ca --- /dev/null +++ b/lib/browser/StorageController.default.js @@ -0,0 +1,41 @@ +"use strict"; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +// When there is no native storage interface, we default to an in-memory map + +var memMap = {}; +var StorageController = { + async: 0, + + getItem: function (path) { + if (memMap.hasOwnProperty(path)) { + return memMap[path]; + } + return null; + }, + setItem: function (path, value) { + memMap[path] = String(value); + }, + removeItem: function (path) { + delete memMap[path]; + }, + clear: function () { + for (var key in memMap) { + if (memMap.hasOwnProperty(key)) { + delete memMap[key]; + } + } + } +}; + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/browser/StorageController.react-native.js b/lib/browser/StorageController.react-native.js new file mode 100644 index 000000000..b92ae6141 --- /dev/null +++ b/lib/browser/StorageController.react-native.js @@ -0,0 +1,67 @@ +'use strict'; + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _reactNative = require('react-native/Libraries/react-native/react-native.js'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var StorageController = { + async: 1, + + getItemAsync: function (path) { + var p = new _ParsePromise2.default(); + _reactNative.AsyncStorage.getItem(path, function (err, value) { + if (err) { + p.reject(err); + } else { + p.resolve(value); + } + }); + return p; + }, + setItemAsync: function (path, value) { + var p = new _ParsePromise2.default(); + _reactNative.AsyncStorage.setItem(path, value, function (err) { + if (err) { + p.reject(err); + } else { + p.resolve(value); + } + }); + return p; + }, + removeItemAsync: function (path) { + var p = new _ParsePromise2.default(); + _reactNative.AsyncStorage.removeItem(path, function (err) { + if (err) { + p.reject(err); + } else { + p.resolve(); + } + }); + return p; + }, + clear: function () { + _reactNative.AsyncStorage.clear(); + } +}; +// RN packager nonsense + + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/browser/TaskQueue.js b/lib/browser/TaskQueue.js new file mode 100644 index 000000000..4bf6bffd0 --- /dev/null +++ b/lib/browser/TaskQueue.js @@ -0,0 +1,77 @@ +'use strict'; + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var TaskQueue = function () { + function TaskQueue() { + (0, _classCallCheck3.default)(this, TaskQueue); + + this.queue = []; + } + + (0, _createClass3.default)(TaskQueue, [{ + key: 'enqueue', + value: function (task) { + var _this = this; + + var taskComplete = new _ParsePromise2.default(); + this.queue.push({ + task: task, + _completion: taskComplete + }); + if (this.queue.length === 1) { + task().then(function () { + _this._dequeue(); + taskComplete.resolve(); + }, function (error) { + _this._dequeue(); + taskComplete.reject(error); + }); + } + return taskComplete; + } + }, { + key: '_dequeue', + value: function () { + var _this2 = this; + + this.queue.shift(); + if (this.queue.length) { + var next = this.queue[0]; + next.task().then(function () { + _this2._dequeue(); + next._completion.resolve(); + }, function (error) { + _this2._dequeue(); + next._completion.reject(error); + }); + } + } + }]); + return TaskQueue; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = TaskQueue; \ No newline at end of file diff --git a/lib/browser/UniqueInstanceStateController.js b/lib/browser/UniqueInstanceStateController.js new file mode 100644 index 000000000..12b8ab04d --- /dev/null +++ b/lib/browser/UniqueInstanceStateController.js @@ -0,0 +1,189 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _weakMap = require('babel-runtime/core-js/weak-map'); + +var _weakMap2 = _interopRequireDefault(_weakMap); + +exports.getState = getState; +exports.initializeState = initializeState; +exports.removeState = removeState; +exports.getServerData = getServerData; +exports.setServerData = setServerData; +exports.getPendingOps = getPendingOps; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.getObjectCache = getObjectCache; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; +exports.enqueueTask = enqueueTask; +exports.duplicateState = duplicateState; +exports.clearAllState = clearAllState; + +var _ObjectStateMutations = require('./ObjectStateMutations'); + +var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); + +var _TaskQueue = require('./TaskQueue'); + +var _TaskQueue2 = _interopRequireDefault(_TaskQueue); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var objectState = new _weakMap2.default(); + +function getState(obj) { + var classData = objectState.get(obj); + return classData || null; +} + +function initializeState(obj, initial) { + var state = getState(obj); + if (state) { + return state; + } + if (!initial) { + initial = { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new _TaskQueue2.default(), + existed: false + }; + } + state = initial; + objectState.set(obj, state); + return state; +} + +function removeState(obj) { + var state = getState(obj); + if (state === null) { + return null; + } + objectState.delete(obj); + return state; +} + +function getServerData(obj) { + var state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +function setServerData(obj, attributes) { + var serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +function getPendingOps(obj) { + var state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +function setPendingOp(obj, attr, op) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +function pushPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +function popPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +function mergeFirstPendingState(obj) { + var pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +function getObjectCache(obj) { + var state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +function estimateAttribute(obj, attr) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +function estimateAttributes(obj) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +function commitServerChanges(obj, changes) { + var state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +function enqueueTask(obj, task) { + var state = initializeState(obj); + return state.tasks.enqueue(task); +} + +function duplicateState(source, dest) { + var oldState = initializeState(source); + var newState = initializeState(dest); + for (var key in oldState.serverData) { + newState.serverData[key] = oldState.serverData[key]; + } + for (var index = 0; index < oldState.pendingOps.length; index++) { + for (var _key in oldState.pendingOps[index]) { + newState.pendingOps[index][_key] = oldState.pendingOps[index][_key]; + } + } + for (var _key2 in oldState.objectCache) { + newState.objectCache[_key2] = oldState.objectCache[_key2]; + } + newState.existed = oldState.existed; +} + +function clearAllState() { + objectState = new _weakMap2.default(); +} \ No newline at end of file diff --git a/lib/browser/arrayContainsObject.js b/lib/browser/arrayContainsObject.js new file mode 100644 index 000000000..e9d7949c9 --- /dev/null +++ b/lib/browser/arrayContainsObject.js @@ -0,0 +1,35 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = arrayContainsObject; + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function arrayContainsObject(array, object) { + if (array.indexOf(object) > -1) { + return true; + } + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof _ParseObject2.default && array[i].className === object.className && array[i]._getId() === object._getId()) { + return true; + } + } + return false; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ \ No newline at end of file diff --git a/lib/browser/canBeSerialized.js b/lib/browser/canBeSerialized.js new file mode 100644 index 000000000..e7b7e2282 --- /dev/null +++ b/lib/browser/canBeSerialized.js @@ -0,0 +1,82 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = canBeSerialized; + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function canBeSerialized(obj) { + if (!(obj instanceof _ParseObject2.default)) { + return true; + } + var attributes = obj.attributes; + for (var attr in attributes) { + var val = attributes[attr]; + if (!canBeSerializedHelper(val)) { + return false; + } + } + return true; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function canBeSerializedHelper(value) { + if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { + return true; + } + if (value instanceof _ParseRelation2.default) { + return true; + } + if (value instanceof _ParseObject2.default) { + return !!value.id; + } + if (value instanceof _ParseFile2.default) { + if (value.url()) { + return true; + } + return false; + } + if (Array.isArray(value)) { + for (var i = 0; i < value.length; i++) { + if (!canBeSerializedHelper(value[i])) { + return false; + } + } + return true; + } + for (var k in value) { + if (!canBeSerializedHelper(value[k])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/browser/decode.js b/lib/browser/decode.js new file mode 100644 index 000000000..98a182789 --- /dev/null +++ b/lib/browser/decode.js @@ -0,0 +1,93 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = decode; + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseOp = require('./ParseOp'); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function decode(value) { + if (value === null || (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { + return value; + } + if (Array.isArray(value)) { + var dup = []; + value.forEach(function (v, i) { + dup[i] = decode(v); + }); + return dup; + } + if (typeof value.__op === 'string') { + return (0, _ParseOp.opFromJSON)(value); + } + if (value.__type === 'Pointer' && value.className) { + return _ParseObject2.default.fromJSON(value); + } + if (value.__type === 'Object' && value.className) { + return _ParseObject2.default.fromJSON(value); + } + if (value.__type === 'Relation') { + // The parent and key fields will be populated by the parent + var relation = new _ParseRelation2.default(null, null); + relation.targetClassName = value.className; + return relation; + } + if (value.__type === 'Date') { + return new Date(value.iso); + } + if (value.__type === 'File') { + return _ParseFile2.default.fromJSON(value); + } + if (value.__type === 'GeoPoint') { + return new _ParseGeoPoint2.default({ + latitude: value.latitude, + longitude: value.longitude + }); + } + var copy = {}; + for (var k in value) { + copy[k] = decode(value[k]); + } + return copy; +} \ No newline at end of file diff --git a/lib/browser/encode.js b/lib/browser/encode.js new file mode 100644 index 000000000..8c3aee6e3 --- /dev/null +++ b/lib/browser/encode.js @@ -0,0 +1,104 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +exports.default = function (value, disallowObjects, forcePointers, seen) { + return encode(value, !!disallowObjects, !!forcePointers, seen || []); +}; + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseOp = require('./ParseOp'); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var toString = Object.prototype.toString; + +function encode(value, disallowObjects, forcePointers, seen) { + if (value instanceof _ParseObject2.default) { + if (disallowObjects) { + throw new Error('Parse Objects not allowed here'); + } + var seenEntry = value.id ? value.className + ':' + value.id : value; + if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || (0, _keys2.default)(value._getServerData()).length < 1) { + return value.toPointer(); + } + seen = seen.concat(seenEntry); + return value._toFullJSON(seen); + } + if (value instanceof _ParseOp.Op || value instanceof _ParseACL2.default || value instanceof _ParseGeoPoint2.default || value instanceof _ParseRelation2.default) { + return value.toJSON(); + } + if (value instanceof _ParseFile2.default) { + if (!value.url()) { + throw new Error('Tried to encode an unsaved file.'); + } + return value.toJSON(); + } + if (toString.call(value) === '[object Date]') { + if (isNaN(value)) { + throw new Error('Tried to encode an invalid date.'); + } + return { __type: 'Date', iso: value.toJSON() }; + } + if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { + return value.source; + } + + if (Array.isArray(value)) { + return value.map(function (v) { + return encode(v, disallowObjects, forcePointers, seen); + }); + } + + if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { + var output = {}; + for (var k in value) { + output[k] = encode(value[k], disallowObjects, forcePointers, seen); + } + return output; + } + + return value; +} \ No newline at end of file diff --git a/lib/browser/equals.js b/lib/browser/equals.js new file mode 100644 index 000000000..32edcc8a7 --- /dev/null +++ b/lib/browser/equals.js @@ -0,0 +1,84 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = equals; + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +function equals(a, b) { + if ((typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== (typeof b === 'undefined' ? 'undefined' : (0, _typeof3.default)(b))) { + return false; + } + + if (!a || (typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== 'object') { + // a is a primitive + return a === b; + } + + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b)) { + return false; + } + if (a.length !== b.length) { + return false; + } + for (var i = a.length; i--;) { + if (!equals(a[i], b[i])) { + return false; + } + } + return true; + } + + if (a instanceof _ParseACL2.default || a instanceof _ParseFile2.default || a instanceof _ParseGeoPoint2.default || a instanceof _ParseObject2.default) { + return a.equals(b); + } + + if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) { + return false; + } + for (var k in a) { + if (!equals(a[k], b[k])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/browser/escape.js b/lib/browser/escape.js new file mode 100644 index 000000000..4693baaed --- /dev/null +++ b/lib/browser/escape.js @@ -0,0 +1,31 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = escape; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var encoded = { + '&': '&', + '<': '<', + '>': '>', + '/': '/', + '\'': ''', + '"': '"' +}; + +function escape(str) { + return str.replace(/[&<>\/'"]/g, function (char) { + return encoded[char]; + }); +} \ No newline at end of file diff --git a/lib/browser/isRevocableSession.js b/lib/browser/isRevocableSession.js new file mode 100644 index 000000000..92b8230e9 --- /dev/null +++ b/lib/browser/isRevocableSession.js @@ -0,0 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = isRevocableSession; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function isRevocableSession(token) { + return token.indexOf('r:') > -1; +} \ No newline at end of file diff --git a/lib/browser/parseDate.js b/lib/browser/parseDate.js new file mode 100644 index 000000000..48e061b05 --- /dev/null +++ b/lib/browser/parseDate.js @@ -0,0 +1,34 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = parseDate; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function parseDate(iso8601) { + var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); + var match = regexp.exec(iso8601); + if (!match) { + return null; + } + + var year = match[1] || 0; + var month = (match[2] || 1) - 1; + var day = match[3] || 0; + var hour = match[4] || 0; + var minute = match[5] || 0; + var second = match[6] || 0; + var milli = match[8] || 0; + + return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); +} \ No newline at end of file diff --git a/lib/browser/unique.js b/lib/browser/unique.js new file mode 100644 index 000000000..157b3560a --- /dev/null +++ b/lib/browser/unique.js @@ -0,0 +1,45 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = unique; + +var _arrayContainsObject = require('./arrayContainsObject'); + +var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function unique(arr) { + var uniques = []; + arr.forEach(function (value) { + if (value instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(uniques, value)) { + uniques.push(value); + } + } else { + if (uniques.indexOf(value) < 0) { + uniques.push(value); + } + } + }); + return uniques; +} \ No newline at end of file diff --git a/lib/browser/unsavedChildren.js b/lib/browser/unsavedChildren.js new file mode 100644 index 000000000..073efd70b --- /dev/null +++ b/lib/browser/unsavedChildren.js @@ -0,0 +1,102 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = unsavedChildren; + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Return an array of unsaved children, which are either Parse Objects or Files. + * If it encounters any dirty Objects without Ids, it will throw an exception. + */ +function unsavedChildren(obj, allowDeepUnsaved) { + var encountered = { + objects: {}, + files: [] + }; + var identifier = obj.className + ':' + obj._getId(); + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if ((0, _typeof3.default)(attributes[attr]) === 'object') { + traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); + } + } + var unsaved = []; + for (var id in encountered.objects) { + if (id !== identifier && encountered.objects[id] !== true) { + unsaved.push(encountered.objects[id]); + } + } + return unsaved.concat(encountered.files); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { + if (obj instanceof _ParseObject2.default) { + if (!obj.id && shouldThrow) { + throw new Error('Cannot create a pointer to an unsaved Object.'); + } + var identifier = obj.className + ':' + obj._getId(); + if (!encountered.objects[identifier]) { + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if ((0, _typeof3.default)(attributes[attr]) === 'object') { + traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); + } + } + } + return; + } + if (obj instanceof _ParseFile2.default) { + if (!obj.url() && encountered.files.indexOf(obj) < 0) { + encountered.files.push(obj); + } + return; + } + if (obj instanceof _ParseRelation2.default) { + return; + } + if (Array.isArray(obj)) { + obj.forEach(function (el) { + if ((typeof el === 'undefined' ? 'undefined' : (0, _typeof3.default)(el)) === 'object') { + traverse(el, encountered, shouldThrow, allowDeepUnsaved); + } + }); + } + for (var k in obj) { + if ((0, _typeof3.default)(obj[k]) === 'object') { + traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); + } + } +} \ No newline at end of file diff --git a/lib/node/Analytics.js b/lib/node/Analytics.js new file mode 100644 index 000000000..e5bddf088 --- /dev/null +++ b/lib/node/Analytics.js @@ -0,0 +1,89 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.track = track; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Parse.Analytics provides an interface to Parse's logging and analytics + * backend. + * + * @class Parse.Analytics + * @static + */ + +/** + * Tracks the occurrence of a custom event with additional dimensions. + * Parse will store a data point at the time of invocation with the given + * event name. + * + * Dimensions will allow segmentation of the occurrences of this custom + * event. Keys and values should be {@code String}s, and will throw + * otherwise. + * + * To track a user signup along with additional metadata, consider the + * following: + *
          + * var dimensions = {
          + *  gender: 'm',
          + *  source: 'web',
          + *  dayType: 'weekend'
          + * };
          + * Parse.Analytics.track('signup', dimensions);
          + * 
          + * + * There is a default limit of 8 dimensions per event tracked. + * + * @method track + * @param {String} name The name of the custom event to report to Parse as + * having happened. + * @param {Object} dimensions The dictionary of information by which to + * segment this event. + * @param {Object} options A Backbone-style callback object. + * @return {Parse.Promise} A promise that is resolved when the round-trip + * to the server completes. + */ +function track(name, dimensions, options) { + name = name || ''; + name = name.replace(/^\s*/, ''); + name = name.replace(/\s*$/, ''); + if (name.length === 0) { + throw new TypeError('A name for the custom event must be provided'); + } + + for (var key in dimensions) { + if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { + throw new TypeError('track() dimensions expects keys and values of type "string".'); + } + } + + options = options || {}; + return _CoreManager2.default.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var DefaultController = { + track: function (name, dimensions) { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); + } +}; + +_CoreManager2.default.setAnalyticsController(DefaultController); \ No newline at end of file diff --git a/lib/node/Cloud.js b/lib/node/Cloud.js new file mode 100644 index 000000000..72c333750 --- /dev/null +++ b/lib/node/Cloud.js @@ -0,0 +1,109 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.run = run; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains functions for calling and declaring + * cloud functions. + *

          + * Some functions are only available from Cloud Code. + *

          + * + * @class Parse.Cloud + * @static + */ + +/** + * Makes a call to a cloud function. + * @method run + * @param {String} name The function name. + * @param {Object} data The parameters to send to the cloud function. + * @param {Object} options A Backbone-style options object + * options.success, if set, should be a function to handle a successful + * call to a cloud function. options.error should be a function that + * handles an error running the cloud function. Both functions are + * optional. Both functions take a single argument. + * @return {Parse.Promise} A promise that will be resolved with the result + * of the function. + */ +function run(name, data, options) { + options = options || {}; + + if (typeof name !== 'string' || name.length === 0) { + throw new TypeError('Cloud function name must be a string.'); + } + + var requestOptions = {}; + if (options.useMasterKey) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.sessionToken) { + requestOptions.sessionToken = options.sessionToken; + } + + return _CoreManager2.default.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var DefaultController = { + run: function (name, data, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + var payload = (0, _encode2.default)(data, true); + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + requestOptions.sessionToken = options.sessionToken; + } + + var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); + + return request.then(function (res) { + var decoded = (0, _decode2.default)(res); + if (decoded && decoded.hasOwnProperty('result')) { + return _ParsePromise2.default.as(decoded.result); + } + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); + })._thenRunCallbacks(options); + } +}; + +_CoreManager2.default.setCloudController(DefaultController); \ No newline at end of file diff --git a/lib/node/CoreManager.js b/lib/node/CoreManager.js new file mode 100644 index 000000000..20d66a5f1 --- /dev/null +++ b/lib/node/CoreManager.js @@ -0,0 +1,161 @@ +'use strict'; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var config = { + // Defaults + IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, + REQUEST_ATTEMPT_LIMIT: 5, + SERVER_URL: 'https://api.parse.com/1', + LIVEQUERY_SERVER_URL: null, + VERSION: 'js' + '1.9.2', + APPLICATION_ID: null, + JAVASCRIPT_KEY: null, + MASTER_KEY: null, + USE_MASTER_KEY: false, + PERFORM_USER_REWRITE: true, + FORCE_REVOCABLE_SESSION: false +}; + +function requireMethods(name, methods, controller) { + methods.forEach(function (func) { + if (typeof controller[func] !== 'function') { + throw new Error(name + ' must implement ' + func + '()'); + } + }); +} + +module.exports = { + get: function (key) { + if (config.hasOwnProperty(key)) { + return config[key]; + } + throw new Error('Configuration key not found: ' + key); + }, + + set: function (key, value) { + config[key] = value; + }, + + /* Specialized Controller Setters/Getters */ + + setAnalyticsController: function (controller) { + requireMethods('AnalyticsController', ['track'], controller); + config['AnalyticsController'] = controller; + }, + getAnalyticsController: function () { + return config['AnalyticsController']; + }, + setCloudController: function (controller) { + requireMethods('CloudController', ['run'], controller); + config['CloudController'] = controller; + }, + getCloudController: function () { + return config['CloudController']; + }, + setConfigController: function (controller) { + requireMethods('ConfigController', ['current', 'get'], controller); + config['ConfigController'] = controller; + }, + getConfigController: function () { + return config['ConfigController']; + }, + setFileController: function (controller) { + requireMethods('FileController', ['saveFile', 'saveBase64'], controller); + config['FileController'] = controller; + }, + getFileController: function () { + return config['FileController']; + }, + setInstallationController: function (controller) { + requireMethods('InstallationController', ['currentInstallationId'], controller); + config['InstallationController'] = controller; + }, + getInstallationController: function () { + return config['InstallationController']; + }, + setObjectController: function (controller) { + requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); + config['ObjectController'] = controller; + }, + getObjectController: function () { + return config['ObjectController']; + }, + setObjectStateController: function (controller) { + requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); + + config['ObjectStateController'] = controller; + }, + getObjectStateController: function () { + return config['ObjectStateController']; + }, + setPushController: function (controller) { + requireMethods('PushController', ['send'], controller); + config['PushController'] = controller; + }, + getPushController: function () { + return config['PushController']; + }, + setQueryController: function (controller) { + requireMethods('QueryController', ['find'], controller); + config['QueryController'] = controller; + }, + getQueryController: function () { + return config['QueryController']; + }, + setRESTController: function (controller) { + requireMethods('RESTController', ['request', 'ajax'], controller); + config['RESTController'] = controller; + }, + getRESTController: function () { + return config['RESTController']; + }, + setSessionController: function (controller) { + requireMethods('SessionController', ['getSession'], controller); + config['SessionController'] = controller; + }, + getSessionController: function () { + return config['SessionController']; + }, + setStorageController: function (controller) { + if (controller.async) { + requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); + } else { + requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); + } + config['StorageController'] = controller; + }, + getStorageController: function () { + return config['StorageController']; + }, + setUserController: function (controller) { + requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); + config['UserController'] = controller; + }, + getUserController: function () { + return config['UserController']; + }, + setLiveQueryController: function (controller) { + requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); + config['LiveQueryController'] = controller; + }, + getLiveQueryController: function () { + return config['LiveQueryController']; + }, + setHooksController: function (controller) { + requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); + config['HooksController'] = controller; + }, + getHooksController: function () { + return config['HooksController']; + } +}; \ No newline at end of file diff --git a/lib/node/EventEmitter.js b/lib/node/EventEmitter.js new file mode 100644 index 000000000..e9414f0bf --- /dev/null +++ b/lib/node/EventEmitter.js @@ -0,0 +1,15 @@ +'use strict'; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * This is a simple wrapper to unify EventEmitter implementations across platforms. + */ + +module.exports = require('events').EventEmitter; +var EventEmitter; \ No newline at end of file diff --git a/lib/node/FacebookUtils.js b/lib/node/FacebookUtils.js new file mode 100644 index 000000000..bb8b7ef51 --- /dev/null +++ b/lib/node/FacebookUtils.js @@ -0,0 +1,243 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _parseDate = require('./parseDate'); + +var _parseDate2 = _interopRequireDefault(_parseDate); + +var _ParseUser = require('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * -weak + */ + +var PUBLIC_KEY = "*"; + +var initialized = false; +var requestedPermissions; +var initOptions; +var provider = { + authenticate: function (options) { + var _this = this; + + if (typeof FB === 'undefined') { + options.error(this, 'Facebook SDK not found.'); + } + FB.login(function (response) { + if (response.authResponse) { + if (options.success) { + options.success(_this, { + id: response.authResponse.userID, + access_token: response.authResponse.accessToken, + expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() + }); + } + } else { + if (options.error) { + options.error(_this, response); + } + } + }, { + scope: requestedPermissions + }); + }, + restoreAuthentication: function (authData) { + if (authData) { + var expiration = (0, _parseDate2.default)(authData.expiration_date); + var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; + + var authResponse = { + userID: authData.id, + accessToken: authData.access_token, + expiresIn: expiresIn + }; + var newOptions = {}; + if (initOptions) { + for (var key in initOptions) { + newOptions[key] = initOptions[key]; + } + } + newOptions.authResponse = authResponse; + + // Suppress checks for login status from the browser. + newOptions.status = false; + + // If the user doesn't match the one known by the FB SDK, log out. + // Most of the time, the users will match -- it's only in cases where + // the FB SDK knows of a different user than the one being restored + // from a Parse User that logged in with username/password. + var existingResponse = FB.getAuthResponse(); + if (existingResponse && existingResponse.userID !== authResponse.userID) { + FB.logout(); + } + + FB.init(newOptions); + } + return true; + }, + getAuthType: function () { + return 'facebook'; + }, + deauthenticate: function () { + this.restoreAuthentication(null); + } +}; + +/** + * Provides a set of utilities for using Parse with Facebook. + * @class Parse.FacebookUtils + * @static + */ +var FacebookUtils = { + /** + * Initializes Parse Facebook integration. Call this function after you + * have loaded the Facebook Javascript SDK with the same parameters + * as you would pass to + * + * FB.init(). Parse.FacebookUtils will invoke FB.init() for you + * with these arguments. + * + * @method init + * @param {Object} options Facebook options argument as described here: + * + * FB.init(). The status flag will be coerced to 'false' because it + * interferes with Parse Facebook integration. Call FB.getLoginStatus() + * explicitly if this behavior is required by your application. + */ + init: function (options) { + if (typeof FB === 'undefined') { + throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); + } + initOptions = {}; + if (options) { + for (var key in options) { + initOptions[key] = options[key]; + } + } + if (initOptions.status && typeof console !== 'undefined') { + var warn = console.warn || console.log || function () {}; + warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); + } + initOptions.status = false; + FB.init(initOptions); + _ParseUser2.default._registerAuthenticationProvider(provider); + initialized = true; + }, + + /** + * Gets whether the user has their account linked to Facebook. + * + * @method isLinked + * @param {Parse.User} user User to check for a facebook link. + * The user must be logged in on this device. + * @return {Boolean} true if the user has their account + * linked to Facebook. + */ + isLinked: function (user) { + return user._isLinked('facebook'); + }, + + /** + * Logs in a user using Facebook. This method delegates to the Facebook + * SDK to authenticate the user, and then automatically logs in (or + * creates, in the case where it is a new user) a Parse.User. + * + * @method logIn + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + logIn: function (permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling logIn.'); + } + requestedPermissions = permissions; + return _ParseUser2.default._logInWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return _ParseUser2.default._logInWith('facebook', newOptions); + } + }, + + /** + * Links Facebook to an existing PFUser. This method delegates to the + * Facebook SDK to authenticate the user, and then automatically links + * the account to the Parse.User. + * + * @method link + * @param {Parse.User} user User to link to Facebook. This must be the + * current user. + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + link: function (user, permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling link.'); + } + requestedPermissions = permissions; + return user._linkWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return user._linkWith('facebook', newOptions); + } + }, + + /** + * Unlinks the Parse.User from a Facebook account. + * + * @method unlink + * @param {Parse.User} user User to unlink from Facebook. This must be the + * current user. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + unlink: function (user, options) { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling unlink.'); + } + return user._unlinkFrom('facebook', options); + } +}; + +exports.default = FacebookUtils; \ No newline at end of file diff --git a/lib/node/InstallationController.js b/lib/node/InstallationController.js new file mode 100644 index 000000000..7b01e3cad --- /dev/null +++ b/lib/node/InstallationController.js @@ -0,0 +1,64 @@ +'use strict'; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var iidCache = null; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function hexOctet() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); +} + +function generateId() { + return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); +} + +var InstallationController = { + currentInstallationId: function () { + if (typeof iidCache === 'string') { + return _ParsePromise2.default.as(iidCache); + } + var path = _Storage2.default.generatePath('installationId'); + return _Storage2.default.getItemAsync(path).then(function (iid) { + if (!iid) { + iid = generateId(); + return _Storage2.default.setItemAsync(path, iid).then(function () { + iidCache = iid; + return iid; + }); + } + iidCache = iid; + return iid; + }); + }, + _clearCache: function () { + iidCache = null; + }, + _setInstallationIdCache: function (iid) { + iidCache = iid; + } +}; + +module.exports = InstallationController; \ No newline at end of file diff --git a/lib/node/LiveQueryClient.js b/lib/node/LiveQueryClient.js new file mode 100644 index 000000000..e0420323f --- /dev/null +++ b/lib/node/LiveQueryClient.js @@ -0,0 +1,595 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getIterator2 = require('babel-runtime/core-js/get-iterator'); + +var _getIterator3 = _interopRequireDefault(_getIterator2); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _map = require('babel-runtime/core-js/map'); + +var _map2 = _interopRequireDefault(_map); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _EventEmitter2 = require('./EventEmitter'); + +var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _LiveQuerySubscription = require('./LiveQuerySubscription'); + +var _LiveQuerySubscription2 = _interopRequireDefault(_LiveQuerySubscription); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +// The LiveQuery client inner state +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +var CLIENT_STATE = { + INITIALIZED: 'initialized', + CONNECTING: 'connecting', + CONNECTED: 'connected', + CLOSED: 'closed', + RECONNECTING: 'reconnecting', + DISCONNECTED: 'disconnected' +}; + +// The event type the LiveQuery client should sent to server +var OP_TYPES = { + CONNECT: 'connect', + SUBSCRIBE: 'subscribe', + UNSUBSCRIBE: 'unsubscribe', + ERROR: 'error' +}; + +// The event we get back from LiveQuery server +var OP_EVENTS = { + CONNECTED: 'connected', + SUBSCRIBED: 'subscribed', + UNSUBSCRIBED: 'unsubscribed', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +// The event the LiveQuery client should emit +var CLIENT_EMMITER_TYPES = { + CLOSE: 'close', + ERROR: 'error', + OPEN: 'open' +}; + +// The event the LiveQuery subscription should emit +var SUBSCRIPTION_EMMITER_TYPES = { + OPEN: 'open', + CLOSE: 'close', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +var generateInterval = function (k) { + return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; +}; + +/** + * Creates a new LiveQueryClient. + * Extends events.EventEmitter + * cloud functions. + * + * A wrapper of a standard WebSocket client. We add several useful methods to + * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. + * + * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries + * to connect to the LiveQuery server + * + * @class Parse.LiveQueryClient + * @constructor + * @param {Object} options + * @param {string} options.applicationId - applicationId of your Parse app + * @param {string} options.serverURL - the URL of your LiveQuery server + * @param {string} options.javascriptKey (optional) + * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) + * @param {string} options.sessionToken (optional) + * + * + * We expose three events to help you monitor the status of the LiveQueryClient. + * + *
          + * let Parse = require('parse/node');
          + * let LiveQueryClient = Parse.LiveQueryClient;
          + * let client = new LiveQueryClient({
          + *   applicationId: '',
          + *   serverURL: '',
          + *   javascriptKey: '',
          + *   masterKey: ''
          + *  });
          + * 
          + * + * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + *
          + * client.on('open', () => {
          + * 
          + * });
          + * + * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + *
          + * client.on('close', () => {
          + * 
          + * });
          + * + * Error - When some network error or LiveQuery server error happens, you'll get this event. + *
          + * client.on('error', (error) => {
          + * 
          + * });
          + * + * + */ + +var LiveQueryClient = function (_EventEmitter) { + (0, _inherits3.default)(LiveQueryClient, _EventEmitter); + + function LiveQueryClient(_ref) { + var applicationId = _ref.applicationId, + serverURL = _ref.serverURL, + javascriptKey = _ref.javascriptKey, + masterKey = _ref.masterKey, + sessionToken = _ref.sessionToken; + (0, _classCallCheck3.default)(this, LiveQueryClient); + + var _this = (0, _possibleConstructorReturn3.default)(this, (LiveQueryClient.__proto__ || (0, _getPrototypeOf2.default)(LiveQueryClient)).call(this)); + + if (!serverURL || serverURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + _this.reconnectHandle = null; + _this.attempts = 1;; + _this.id = 0; + _this.requestId = 1; + _this.serverURL = serverURL; + _this.applicationId = applicationId; + _this.javascriptKey = javascriptKey; + _this.masterKey = masterKey; + _this.sessionToken = sessionToken; + _this.connectPromise = new _ParsePromise2.default(); + _this.subscriptions = new _map2.default(); + _this.state = CLIENT_STATE.INITIALIZED; + return _this; + } + + (0, _createClass3.default)(LiveQueryClient, [{ + key: 'shouldOpen', + value: function () { + return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; + } + + /** + * Subscribes to a ParseQuery + * + * If you provide the sessionToken, when the LiveQuery server gets ParseObject's + * updates from parse server, it'll try to check whether the sessionToken fulfills + * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose + * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol + * here for more details. The subscription you get is the same subscription you get + * from our Standard API. + * + * @method subscribe + * @param {Object} query - the ParseQuery you want to subscribe to + * @param {string} sessionToken (optional) + * @return {Object} subscription + */ + + }, { + key: 'subscribe', + value: function (query, sessionToken) { + var _this2 = this; + + if (!query) { + return; + } + var where = query.toJSON().where; + var className = query.className; + var subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: this.requestId, + query: { + className: className, + where: where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + var subscription = new _LiveQuerySubscription2.default(this.requestId, query, sessionToken); + this.subscriptions.set(this.requestId, subscription); + this.requestId += 1; + this.connectPromise.then(function () { + _this2.socket.send((0, _stringify2.default)(subscribeRequest)); + }); + + // adding listener so process does not crash + // best practice is for developer to register their own listener + subscription.on('error', function () {}); + + return subscription; + } + + /** + * After calling unsubscribe you'll stop receiving events from the subscription object. + * + * @method unsubscribe + * @param {Object} subscription - subscription you would like to unsubscribe from. + */ + + }, { + key: 'unsubscribe', + value: function (subscription) { + var _this3 = this; + + if (!subscription) { + return; + } + + this.subscriptions.delete(subscription.id); + var unsubscribeRequest = { + op: OP_TYPES.UNSUBSCRIBE, + requestId: subscription.id + }; + this.connectPromise.then(function () { + _this3.socket.send((0, _stringify2.default)(unsubscribeRequest)); + }); + } + + /** + * After open is called, the LiveQueryClient will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ + + }, { + key: 'open', + value: function () { + var _this4 = this; + + var WebSocketImplementation = this._getWebSocketImplementation(); + if (!WebSocketImplementation) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); + return; + } + + if (this.state !== CLIENT_STATE.RECONNECTING) { + this.state = CLIENT_STATE.CONNECTING; + } + + // Get WebSocket implementation + this.socket = new WebSocketImplementation(this.serverURL); + + // Bind WebSocket callbacks + this.socket.onopen = function () { + _this4._handleWebSocketOpen(); + }; + + this.socket.onmessage = function (event) { + _this4._handleWebSocketMessage(event); + }; + + this.socket.onclose = function () { + _this4._handleWebSocketClose(); + }; + + this.socket.onerror = function (error) { + _this4._handleWebSocketError(error); + }; + } + }, { + key: 'resubscribe', + value: function () { + var _this5 = this; + + this.subscriptions.forEach(function (subscription, requestId) { + var query = subscription.query; + var where = query.toJSON().where; + var className = query.className; + var sessionToken = subscription.sessionToken; + var subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: requestId, + query: { + className: className, + where: where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + _this5.connectPromise.then(function () { + _this5.socket.send((0, _stringify2.default)(subscribeRequest)); + }); + }); + } + + /** + * This method will close the WebSocket connection to this LiveQueryClient, + * cancel the auto reconnect and unsubscribe all subscriptions based on it. + * + * @method close + */ + + }, { + key: 'close', + value: function () { + if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.DISCONNECTED; + this.socket.close(); + // Notify each subscription about the close + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = (0, _getIterator3.default)(this.subscriptions.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var subscription = _step.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + this._handleReset(); + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + } + }, { + key: '_getWebSocketImplementation', + value: function () { + return require('ws'); + } + + // ensure we start with valid state if connect is called again after close + + }, { + key: '_handleReset', + value: function () { + this.attempts = 1;; + this.id = 0; + this.requestId = 1; + this.connectPromise = new _ParsePromise2.default(); + this.subscriptions = new _map2.default(); + } + }, { + key: '_handleWebSocketOpen', + value: function () { + this.attempts = 1; + var connectRequest = { + op: OP_TYPES.CONNECT, + applicationId: this.applicationId, + javascriptKey: this.javascriptKey, + masterKey: this.masterKey, + sessionToken: this.sessionToken + }; + this.socket.send((0, _stringify2.default)(connectRequest)); + } + }, { + key: '_handleWebSocketMessage', + value: function (event) { + var data = event.data; + if (typeof data === 'string') { + data = JSON.parse(data); + } + var subscription = null; + if (data.requestId) { + subscription = this.subscriptions.get(data.requestId); + } + switch (data.op) { + case OP_EVENTS.CONNECTED: + if (this.state === CLIENT_STATE.RECONNECTING) { + this.resubscribe(); + } + this.emit(CLIENT_EMMITER_TYPES.OPEN); + this.id = data.clientId; + this.connectPromise.resolve(); + this.state = CLIENT_STATE.CONNECTED; + break; + case OP_EVENTS.SUBSCRIBED: + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); + } + break; + case OP_EVENTS.ERROR: + if (data.requestId) { + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); + } + } else { + this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); + } + break; + case OP_EVENTS.UNSUBSCRIBED: + // We have already deleted subscription in unsubscribe(), do nothing here + break; + default: + // create, update, enter, leave, delete cases + var className = data.object.className; + // Delete the extrea __type and className fields during transfer to full JSON + delete data.object.__type; + delete data.object.className; + var parseObject = new _ParseObject2.default(className); + parseObject._finishFetch(data.object); + if (!subscription) { + break; + } + subscription.emit(data.op, parseObject); + } + } + }, { + key: '_handleWebSocketClose', + value: function () { + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.CLOSED; + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + // Notify each subscription about the close + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = (0, _getIterator3.default)(this.subscriptions.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var subscription = _step2.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + this._handleReconnect(); + } + }, { + key: '_handleWebSocketError', + value: function (error) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, error); + var _iteratorNormalCompletion3 = true; + var _didIteratorError3 = false; + var _iteratorError3 = undefined; + + try { + for (var _iterator3 = (0, _getIterator3.default)(this.subscriptions.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { + var subscription = _step3.value; + + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); + } + } catch (err) { + _didIteratorError3 = true; + _iteratorError3 = err; + } finally { + try { + if (!_iteratorNormalCompletion3 && _iterator3.return) { + _iterator3.return(); + } + } finally { + if (_didIteratorError3) { + throw _iteratorError3; + } + } + } + + this._handleReconnect(); + } + }, { + key: '_handleReconnect', + value: function () { + var _this6 = this; + + // if closed or currently reconnecting we stop attempting to reconnect + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + + this.state = CLIENT_STATE.RECONNECTING; + var time = generateInterval(this.attempts); + + // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. + // we're unable to distinguish different between close/error when we're unable to reconnect therefore + // we try to reonnect in both cases + // server side ws and browser WebSocket behave differently in when close/error get triggered + + if (this.reconnectHandle) { + clearTimeout(this.reconnectHandle); + } + + this.reconnectHandle = setTimeout(function () { + _this6.attempts++; + _this6.connectPromise = new _ParsePromise2.default(); + _this6.open(); + }.bind(this), time); + } + }]); + return LiveQueryClient; +}(_EventEmitter3.default); + +exports.default = LiveQueryClient; \ No newline at end of file diff --git a/lib/node/LiveQuerySubscription.js b/lib/node/LiveQuerySubscription.js new file mode 100644 index 000000000..4078b65d5 --- /dev/null +++ b/lib/node/LiveQuerySubscription.js @@ -0,0 +1,162 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _EventEmitter2 = require('./EventEmitter'); + +var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new LiveQuery Subscription. + * Extends events.EventEmitter + * cloud functions. + * + * @constructor + * @param {string} id - subscription id + * @param {string} query - query to subscribe to + * @param {string} sessionToken - optional session token + * + *

          Open Event - When you call query.subscribe(), we send a subscribe request to + * the LiveQuery server, when we get the confirmation from the LiveQuery server, + * this event will be emitted. When the client loses WebSocket connection to the + * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we + * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, + * you'll also get this event. + * + *

          + * subscription.on('open', () => {
          + * 
          + * });

          + * + *

          Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, + * you'll get this event. The object is the ParseObject which is created. + * + *

          + * subscription.on('create', (object) => {
          + * 
          + * });

          + * + *

          Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe + * is updated (The ParseObject fulfills the ParseQuery before and after changes), + * you'll get this event. The object is the ParseObject which is updated. + * Its content is the latest value of the ParseObject. + * + *

          + * subscription.on('update', (object) => {
          + * 
          + * });

          + * + *

          Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery + * but its new value fulfills the ParseQuery, you'll get this event. The object is the + * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. + * + *

          + * subscription.on('enter', (object) => {
          + * 
          + * });

          + * + * + *

          Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value + * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject + * which leaves the ParseQuery. Its content is the latest value of the ParseObject. + * + *

          + * subscription.on('leave', (object) => {
          + * 
          + * });

          + * + * + *

          Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll + * get this event. The object is the ParseObject which is deleted. + * + *

          + * subscription.on('delete', (object) => {
          + * 
          + * });

          + * + * + *

          Close Event - When the client loses the WebSocket connection to the LiveQuery + * server and we stop receiving events, you'll get this event. + * + *

          + * subscription.on('close', () => {
          + * 
          + * });

          + * + * + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +var Subscription = function (_EventEmitter) { + (0, _inherits3.default)(Subscription, _EventEmitter); + + function Subscription(id, query, sessionToken) { + (0, _classCallCheck3.default)(this, Subscription); + + var _this2 = (0, _possibleConstructorReturn3.default)(this, (Subscription.__proto__ || (0, _getPrototypeOf2.default)(Subscription)).call(this)); + + _this2.id = id; + _this2.query = query; + _this2.sessionToken = sessionToken; + return _this2; + } + + /** + * @method unsubscribe + */ + + (0, _createClass3.default)(Subscription, [{ + key: 'unsubscribe', + value: function () { + var _this3 = this; + + var _this = this; + _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient().then(function (liveQueryClient) { + liveQueryClient.unsubscribe(_this); + _this.emit('close'); + _this3.resolve(); + }); + } + }]); + return Subscription; +}(_EventEmitter3.default); + +exports.default = Subscription; \ No newline at end of file diff --git a/lib/node/ObjectStateMutations.js b/lib/node/ObjectStateMutations.js new file mode 100644 index 000000000..b476a0e2f --- /dev/null +++ b/lib/node/ObjectStateMutations.js @@ -0,0 +1,165 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.defaultState = defaultState; +exports.setServerData = setServerData; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _TaskQueue = require('./TaskQueue'); + +var _TaskQueue2 = _interopRequireDefault(_TaskQueue); + +var _ParseOp = require('./ParseOp'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function defaultState() { + return { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new _TaskQueue2.default(), + existed: false + }; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function setServerData(serverData, attributes) { + for (var _attr in attributes) { + if (typeof attributes[_attr] !== 'undefined') { + serverData[_attr] = attributes[_attr]; + } else { + delete serverData[_attr]; + } + } +} + +function setPendingOp(pendingOps, attr, op) { + var last = pendingOps.length - 1; + if (op) { + pendingOps[last][attr] = op; + } else { + delete pendingOps[last][attr]; + } +} + +function pushPendingState(pendingOps) { + pendingOps.push({}); +} + +function popPendingState(pendingOps) { + var first = pendingOps.shift(); + if (!pendingOps.length) { + pendingOps[0] = {}; + } + return first; +} + +function mergeFirstPendingState(pendingOps) { + var first = popPendingState(pendingOps); + var next = pendingOps[0]; + for (var _attr2 in first) { + if (next[_attr2] && first[_attr2]) { + var merged = next[_attr2].mergeWith(first[_attr2]); + if (merged) { + next[_attr2] = merged; + } + } else { + next[_attr2] = first[_attr2]; + } + } +} + +function estimateAttribute(serverData, pendingOps, className, id, attr) { + var value = serverData[attr]; + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i][attr]) { + if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { + if (id) { + value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); + } + } else { + value = pendingOps[i][attr].applyTo(value); + } + } + } + return value; +} + +function estimateAttributes(serverData, pendingOps, className, id) { + var data = {}; + var attr = void 0; + for (attr in serverData) { + data[attr] = serverData[attr]; + } + for (var i = 0; i < pendingOps.length; i++) { + for (attr in pendingOps[i]) { + if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { + if (id) { + data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); + } + } else { + data[attr] = pendingOps[i][attr].applyTo(data[attr]); + } + } + } + return data; +} + +function commitServerChanges(serverData, objectCache, changes) { + for (var _attr3 in changes) { + var val = changes[_attr3]; + serverData[_attr3] = val; + if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof _ParseObject2.default) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { + var json = (0, _encode2.default)(val, false, true); + objectCache[_attr3] = (0, _stringify2.default)(json); + } + } +} \ No newline at end of file diff --git a/lib/node/Parse.js b/lib/node/Parse.js new file mode 100644 index 000000000..280cd4015 --- /dev/null +++ b/lib/node/Parse.js @@ -0,0 +1,190 @@ +'use strict'; + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _InstallationController = require('./InstallationController'); + +var _InstallationController2 = _interopRequireDefault(_InstallationController); + +var _ParseOp = require('./ParseOp'); + +var ParseOp = _interopRequireWildcard(_ParseOp); + +var _RESTController = require('./RESTController'); + +var _RESTController2 = _interopRequireDefault(_RESTController); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains all Parse API classes and functions. + * @class Parse + * @static + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var Parse = { + /** + * Call this method first to set up your authentication tokens for Parse. + * You can get your keys from the Data Browser on parse.com. + * @method initialize + * @param {String} applicationId Your Parse Application ID. + * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) + * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) + * @static + */ + initialize: function (applicationId, javaScriptKey) { + Parse._initialize(applicationId, javaScriptKey); + }, + _initialize: function (applicationId, javaScriptKey, masterKey) { + _CoreManager2.default.set('APPLICATION_ID', applicationId); + _CoreManager2.default.set('JAVASCRIPT_KEY', javaScriptKey); + _CoreManager2.default.set('MASTER_KEY', masterKey); + _CoreManager2.default.set('USE_MASTER_KEY', false); + } +}; + +/** These legacy setters may eventually be deprecated **/ +Object.defineProperty(Parse, 'applicationId', { + get: function () { + return _CoreManager2.default.get('APPLICATION_ID'); + }, + set: function (value) { + _CoreManager2.default.set('APPLICATION_ID', value); + } +}); +Object.defineProperty(Parse, 'javaScriptKey', { + get: function () { + return _CoreManager2.default.get('JAVASCRIPT_KEY'); + }, + set: function (value) { + _CoreManager2.default.set('JAVASCRIPT_KEY', value); + } +}); +Object.defineProperty(Parse, 'masterKey', { + get: function () { + return _CoreManager2.default.get('MASTER_KEY'); + }, + set: function (value) { + _CoreManager2.default.set('MASTER_KEY', value); + } +}); +Object.defineProperty(Parse, 'serverURL', { + get: function () { + return _CoreManager2.default.get('SERVER_URL'); + }, + set: function (value) { + _CoreManager2.default.set('SERVER_URL', value); + } +}); +Object.defineProperty(Parse, 'liveQueryServerURL', { + get: function () { + return _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); + }, + set: function (value) { + _CoreManager2.default.set('LIVEQUERY_SERVER_URL', value); + } +}); +/** End setters **/ + +Parse.ACL = require('./ParseACL').default; +Parse.Analytics = require('./Analytics'); +Parse.Cloud = require('./Cloud'); +Parse.CoreManager = require('./CoreManager'); +Parse.Config = require('./ParseConfig').default; +Parse.Error = require('./ParseError').default; +Parse.FacebookUtils = require('./FacebookUtils').default; +Parse.File = require('./ParseFile').default; +Parse.GeoPoint = require('./ParseGeoPoint').default; +Parse.Installation = require('./ParseInstallation').default; +Parse.Object = require('./ParseObject').default; +Parse.Op = { + Set: ParseOp.SetOp, + Unset: ParseOp.UnsetOp, + Increment: ParseOp.IncrementOp, + Add: ParseOp.AddOp, + Remove: ParseOp.RemoveOp, + AddUnique: ParseOp.AddUniqueOp, + Relation: ParseOp.RelationOp +}; +Parse.Promise = require('./ParsePromise').default; +Parse.Push = require('./Push'); +Parse.Query = require('./ParseQuery').default; +Parse.Relation = require('./ParseRelation').default; +Parse.Role = require('./ParseRole').default; +Parse.Session = require('./ParseSession').default; +Parse.Storage = require('./Storage'); +Parse.User = require('./ParseUser').default; +Parse.LiveQuery = require('./ParseLiveQuery').default; +Parse.LiveQueryClient = require('./LiveQueryClient').default; + +Parse._request = function () { + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return _CoreManager2.default.getRESTController().request.apply(null, args); +}; +Parse._ajax = function () { + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return _CoreManager2.default.getRESTController().ajax.apply(null, args); +}; +// We attempt to match the signatures of the legacy versions of these methods +Parse._decode = function (_, value) { + return (0, _decode2.default)(value); +}; +Parse._encode = function (value, _, disallowObjects) { + return (0, _encode2.default)(value, disallowObjects); +}; +Parse._getInstallationId = function () { + return _CoreManager2.default.getInstallationController().currentInstallationId(); +}; + +_CoreManager2.default.setInstallationController(_InstallationController2.default); +_CoreManager2.default.setRESTController(_RESTController2.default); + +Parse.initialize = Parse._initialize; +Parse.Cloud = Parse.Cloud || {}; +Parse.Cloud.useMasterKey = function () { + _CoreManager2.default.set('USE_MASTER_KEY', true); +}; +Parse.Hooks = require('./ParseHooks'); + +// For legacy requires, of the form `var Parse = require('parse').Parse` +Parse.Parse = Parse; + +module.exports = Parse; \ No newline at end of file diff --git a/lib/node/ParseACL.js b/lib/node/ParseACL.js new file mode 100644 index 000000000..2aa232c18 --- /dev/null +++ b/lib/node/ParseACL.js @@ -0,0 +1,406 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParseRole = require('./ParseRole'); + +var _ParseRole2 = _interopRequireDefault(_ParseRole); + +var _ParseUser = require('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var PUBLIC_KEY = '*'; + +/** + * Creates a new ACL. + * If no argument is given, the ACL has no permissions for anyone. + * If the argument is a Parse.User, the ACL will have read and write + * permission for only that user. + * If the argument is any other JSON object, that object will be interpretted + * as a serialized ACL created with toJSON(). + * @class Parse.ACL + * @constructor + * + *

          An ACL, or Access Control List can be added to any + * Parse.Object to restrict access to only a subset of users + * of your application.

          + */ + +var ParseACL = function () { + function ParseACL(arg1) { + (0, _classCallCheck3.default)(this, ParseACL); + + this.permissionsById = {}; + if (arg1 && (typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { + if (arg1 instanceof _ParseUser2.default) { + this.setReadAccess(arg1, true); + this.setWriteAccess(arg1, true); + } else { + for (var userId in arg1) { + var accessList = arg1[userId]; + if (typeof userId !== 'string') { + throw new TypeError('Tried to create an ACL with an invalid user id.'); + } + this.permissionsById[userId] = {}; + for (var permission in accessList) { + var allowed = accessList[permission]; + if (permission !== 'read' && permission !== 'write') { + throw new TypeError('Tried to create an ACL with an invalid permission type.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('Tried to create an ACL with an invalid permission value.'); + } + this.permissionsById[userId][permission] = allowed; + } + } + } + } else if (typeof arg1 === 'function') { + throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); + } + } + + /** + * Returns a JSON-encoded version of the ACL. + * @method toJSON + * @return {Object} + */ + + (0, _createClass3.default)(ParseACL, [{ + key: 'toJSON', + value: function () { + var permissions = {}; + for (var p in this.permissionsById) { + permissions[p] = this.permissionsById[p]; + } + return permissions; + } + + /** + * Returns whether this ACL is equal to another object + * @method equals + * @param other The other object to compare to + * @return {Boolean} + */ + + }, { + key: 'equals', + value: function (other) { + if (!(other instanceof ParseACL)) { + return false; + } + var users = (0, _keys2.default)(this.permissionsById); + var otherUsers = (0, _keys2.default)(other.permissionsById); + if (users.length !== otherUsers.length) { + return false; + } + for (var u in this.permissionsById) { + if (!other.permissionsById[u]) { + return false; + } + if (this.permissionsById[u].read !== other.permissionsById[u].read) { + return false; + } + if (this.permissionsById[u].write !== other.permissionsById[u].write) { + return false; + } + } + return true; + } + }, { + key: '_setAccess', + value: function (accessType, userId, allowed) { + if (userId instanceof _ParseUser2.default) { + userId = userId.id; + } else if (userId instanceof _ParseRole2.default) { + var name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + if (typeof userId !== 'string') { + throw new TypeError('userId must be a string.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('allowed must be either true or false.'); + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + if (!allowed) { + // The user already doesn't have this permission, so no action is needed + return; + } else { + permissions = {}; + this.permissionsById[userId] = permissions; + } + } + + if (allowed) { + this.permissionsById[userId][accessType] = true; + } else { + delete permissions[accessType]; + if ((0, _keys2.default)(permissions).length === 0) { + delete this.permissionsById[userId]; + } + } + } + }, { + key: '_getAccess', + value: function (accessType, userId) { + if (userId instanceof _ParseUser2.default) { + userId = userId.id; + if (!userId) { + throw new Error('Cannot get access for a ParseUser without an ID'); + } + } else if (userId instanceof _ParseRole2.default) { + var name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + return false; + } + return !!permissions[accessType]; + } + + /** + * Sets whether the given user is allowed to read this object. + * @method setReadAccess + * @param userId An instance of Parse.User or its objectId. + * @param {Boolean} allowed Whether that user should have read access. + */ + + }, { + key: 'setReadAccess', + value: function (userId, allowed) { + this._setAccess('read', userId, allowed); + } + + /** + * Get whether the given user id is *explicitly* allowed to read this object. + * Even if this returns false, the user may still be able to access it if + * getPublicReadAccess returns true or a role that the user belongs to has + * write access. + * @method getReadAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + + }, { + key: 'getReadAccess', + value: function (userId) { + return this._getAccess('read', userId); + } + + /** + * Sets whether the given user id is allowed to write this object. + * @method setWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. + * @param {Boolean} allowed Whether that user should have write access. + */ + + }, { + key: 'setWriteAccess', + value: function (userId, allowed) { + this._setAccess('write', userId, allowed); + } + + /** + * Gets whether the given user id is *explicitly* allowed to write this object. + * Even if this returns false, the user may still be able to write it if + * getPublicWriteAccess returns true or a role that the user belongs to has + * write access. + * @method getWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + + }, { + key: 'getWriteAccess', + value: function (userId) { + return this._getAccess('write', userId); + } + + /** + * Sets whether the public is allowed to read this object. + * @method setPublicReadAccess + * @param {Boolean} allowed + */ + + }, { + key: 'setPublicReadAccess', + value: function (allowed) { + this.setReadAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to read this object. + * @method getPublicReadAccess + * @return {Boolean} + */ + + }, { + key: 'getPublicReadAccess', + value: function () { + return this.getReadAccess(PUBLIC_KEY); + } + + /** + * Sets whether the public is allowed to write this object. + * @method setPublicWriteAccess + * @param {Boolean} allowed + */ + + }, { + key: 'setPublicWriteAccess', + value: function (allowed) { + this.setWriteAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to write this object. + * @method getPublicWriteAccess + * @return {Boolean} + */ + + }, { + key: 'getPublicWriteAccess', + value: function () { + return this.getWriteAccess(PUBLIC_KEY); + } + + /** + * Gets whether users belonging to the given role are allowed + * to read this object. Even if this returns false, the role may + * still be able to write it if a parent role has read access. + * + * @method getRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has read access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'getRoleReadAccess', + value: function (role) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getReadAccess('role:' + role); + } + + /** + * Gets whether users belonging to the given role are allowed + * to write this object. Even if this returns false, the role may + * still be able to write it if a parent role has write access. + * + * @method getRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has write access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'getRoleWriteAccess', + value: function (role) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getWriteAccess('role:' + role); + } + + /** + * Sets whether users belonging to the given role are allowed + * to read this object. + * + * @method setRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can read this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'setRoleReadAccess', + value: function (role, allowed) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setReadAccess('role:' + role, allowed); + } + + /** + * Sets whether users belonging to the given role are allowed + * to write this object. + * + * @method setRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can write this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + + }, { + key: 'setRoleWriteAccess', + value: function (role, allowed) { + if (role instanceof _ParseRole2.default) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setWriteAccess('role:' + role, allowed); + } + }]); + return ParseACL; +}(); + +exports.default = ParseACL; \ No newline at end of file diff --git a/lib/node/ParseConfig.js b/lib/node/ParseConfig.js new file mode 100644 index 000000000..925e3a864 --- /dev/null +++ b/lib/node/ParseConfig.js @@ -0,0 +1,228 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _escape2 = require('./escape'); + +var _escape3 = _interopRequireDefault(_escape2); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Parse.Config is a local representation of configuration data that + * can be set from the Parse dashboard. + * + * @class Parse.Config + * @constructor + */ + +var ParseConfig = function () { + function ParseConfig() { + (0, _classCallCheck3.default)(this, ParseConfig); + + this.attributes = {}; + this._escapedAttributes = {}; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The name of an attribute. + */ + + (0, _createClass3.default)(ParseConfig, [{ + key: 'get', + value: function (attr) { + return this.attributes[attr]; + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The name of an attribute. + */ + + }, { + key: 'escape', + value: function (attr) { + var html = this._escapedAttributes[attr]; + if (html) { + return html; + } + var val = this.attributes[attr]; + var escaped = ''; + if (val != null) { + escaped = (0, _escape3.default)(val.toString()); + } + this._escapedAttributes[attr] = escaped; + return escaped; + } + + /** + * Retrieves the most recently-fetched configuration object, either from + * memory or from local storage if necessary. + * + * @method current + * @static + * @return {Config} The most recently-fetched Parse.Config if it + * exists, else an empty Parse.Config. + */ + + }], [{ + key: 'current', + value: function () { + var controller = _CoreManager2.default.getConfigController(); + return controller.current(); + } + + /** + * Gets a new configuration object from the server. + * @method get + * @static + * @param {Object} options A Backbone-style options object. + * Valid options are:
            + *
          • success: Function to call when the get completes successfully. + *
          • error: Function to call when the get fails. + *
          + * @return {Parse.Promise} A promise that is resolved with a newly-created + * configuration object when the get completes. + */ + + }, { + key: 'get', + value: function (options) { + options = options || {}; + + var controller = _CoreManager2.default.getConfigController(); + return controller.get()._thenRunCallbacks(options); + } + }]); + return ParseConfig; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseConfig; + +var currentConfig = null; + +var CURRENT_CONFIG_KEY = 'currentConfig'; + +function decodePayload(data) { + try { + var json = JSON.parse(data); + if (json && (typeof json === 'undefined' ? 'undefined' : (0, _typeof3.default)(json)) === 'object') { + return (0, _decode2.default)(json); + } + } catch (e) { + return null; + } +} + +var DefaultController = { + current: function () { + if (currentConfig) { + return currentConfig; + } + + var config = new ParseConfig(); + var storagePath = _Storage2.default.generatePath(CURRENT_CONFIG_KEY); + var configData; + if (!_Storage2.default.async()) { + configData = _Storage2.default.getItem(storagePath); + + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + } + // Return a promise for async storage controllers + return _Storage2.default.getItemAsync(storagePath).then(function (configData) { + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + }); + }, + get: function () { + var RESTController = _CoreManager2.default.getRESTController(); + + return RESTController.request('GET', 'config', {}, {}).then(function (response) { + if (!response || !response.params) { + var error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Config JSON response invalid.'); + return _ParsePromise2.default.error(error); + } + + var config = new ParseConfig(); + config.attributes = {}; + for (var attr in response.params) { + config.attributes[attr] = (0, _decode2.default)(response.params[attr]); + } + currentConfig = config; + return _Storage2.default.setItemAsync(_Storage2.default.generatePath(CURRENT_CONFIG_KEY), (0, _stringify2.default)(response.params)).then(function () { + return config; + }); + }); + } +}; + +_CoreManager2.default.setConfigController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseError.js b/lib/node/ParseError.js new file mode 100644 index 000000000..b3bad4512 --- /dev/null +++ b/lib/node/ParseError.js @@ -0,0 +1,507 @@ +"use strict"; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * Constructs a new Parse.Error object with the given code and message. + * @class Parse.Error + * @constructor + * @param {Number} code An error code constant from Parse.Error. + * @param {String} message A detailed description of the error. + */ +var ParseError = function ParseError(code, message) { + (0, _classCallCheck3.default)(this, ParseError); + + this.code = code; + this.message = message; +}; + +/** + * Error code indicating some error other than those enumerated here. + * @property OTHER_CAUSE + * @static + * @final + */ + +exports.default = ParseError; +ParseError.OTHER_CAUSE = -1; + +/** + * Error code indicating that something has gone wrong with the server. + * If you get this error code, it is Parse's fault. Contact us at + * https://parse.com/help + * @property INTERNAL_SERVER_ERROR + * @static + * @final + */ +ParseError.INTERNAL_SERVER_ERROR = 1; + +/** + * Error code indicating the connection to the Parse servers failed. + * @property CONNECTION_FAILED + * @static + * @final + */ +ParseError.CONNECTION_FAILED = 100; + +/** + * Error code indicating the specified object doesn't exist. + * @property OBJECT_NOT_FOUND + * @static + * @final + */ +ParseError.OBJECT_NOT_FOUND = 101; + +/** + * Error code indicating you tried to query with a datatype that doesn't + * support it, like exact matching an array or object. + * @property INVALID_QUERY + * @static + * @final + */ +ParseError.INVALID_QUERY = 102; + +/** + * Error code indicating a missing or invalid classname. Classnames are + * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the + * only valid characters. + * @property INVALID_CLASS_NAME + * @static + * @final + */ +ParseError.INVALID_CLASS_NAME = 103; + +/** + * Error code indicating an unspecified object id. + * @property MISSING_OBJECT_ID + * @static + * @final + */ +ParseError.MISSING_OBJECT_ID = 104; + +/** + * Error code indicating an invalid key name. Keys are case-sensitive. They + * must start with a letter, and a-zA-Z0-9_ are the only valid characters. + * @property INVALID_KEY_NAME + * @static + * @final + */ +ParseError.INVALID_KEY_NAME = 105; + +/** + * Error code indicating a malformed pointer. You should not see this unless + * you have been mucking about changing internal Parse code. + * @property INVALID_POINTER + * @static + * @final + */ +ParseError.INVALID_POINTER = 106; + +/** + * Error code indicating that badly formed JSON was received upstream. This + * either indicates you have done something unusual with modifying how + * things encode to JSON, or the network is failing badly. + * @property INVALID_JSON + * @static + * @final + */ +ParseError.INVALID_JSON = 107; + +/** + * Error code indicating that the feature you tried to access is only + * available internally for testing purposes. + * @property COMMAND_UNAVAILABLE + * @static + * @final + */ +ParseError.COMMAND_UNAVAILABLE = 108; + +/** + * You must call Parse.initialize before using the Parse library. + * @property NOT_INITIALIZED + * @static + * @final + */ +ParseError.NOT_INITIALIZED = 109; + +/** + * Error code indicating that a field was set to an inconsistent type. + * @property INCORRECT_TYPE + * @static + * @final + */ +ParseError.INCORRECT_TYPE = 111; + +/** + * Error code indicating an invalid channel name. A channel name is either + * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ + * characters and starts with a letter. + * @property INVALID_CHANNEL_NAME + * @static + * @final + */ +ParseError.INVALID_CHANNEL_NAME = 112; + +/** + * Error code indicating that push is misconfigured. + * @property PUSH_MISCONFIGURED + * @static + * @final + */ +ParseError.PUSH_MISCONFIGURED = 115; + +/** + * Error code indicating that the object is too large. + * @property OBJECT_TOO_LARGE + * @static + * @final + */ +ParseError.OBJECT_TOO_LARGE = 116; + +/** + * Error code indicating that the operation isn't allowed for clients. + * @property OPERATION_FORBIDDEN + * @static + * @final + */ +ParseError.OPERATION_FORBIDDEN = 119; + +/** + * Error code indicating the result was not found in the cache. + * @property CACHE_MISS + * @static + * @final + */ +ParseError.CACHE_MISS = 120; + +/** + * Error code indicating that an invalid key was used in a nested + * JSONObject. + * @property INVALID_NESTED_KEY + * @static + * @final + */ +ParseError.INVALID_NESTED_KEY = 121; + +/** + * Error code indicating that an invalid filename was used for ParseFile. + * A valid file name contains only a-zA-Z0-9_. characters and is between 1 + * and 128 characters. + * @property INVALID_FILE_NAME + * @static + * @final + */ +ParseError.INVALID_FILE_NAME = 122; + +/** + * Error code indicating an invalid ACL was provided. + * @property INVALID_ACL + * @static + * @final + */ +ParseError.INVALID_ACL = 123; + +/** + * Error code indicating that the request timed out on the server. Typically + * this indicates that the request is too expensive to run. + * @property TIMEOUT + * @static + * @final + */ +ParseError.TIMEOUT = 124; + +/** + * Error code indicating that the email address was invalid. + * @property INVALID_EMAIL_ADDRESS + * @static + * @final + */ +ParseError.INVALID_EMAIL_ADDRESS = 125; + +/** + * Error code indicating a missing content type. + * @property MISSING_CONTENT_TYPE + * @static + * @final + */ +ParseError.MISSING_CONTENT_TYPE = 126; + +/** + * Error code indicating a missing content length. + * @property MISSING_CONTENT_LENGTH + * @static + * @final + */ +ParseError.MISSING_CONTENT_LENGTH = 127; + +/** + * Error code indicating an invalid content length. + * @property INVALID_CONTENT_LENGTH + * @static + * @final + */ +ParseError.INVALID_CONTENT_LENGTH = 128; + +/** + * Error code indicating a file that was too large. + * @property FILE_TOO_LARGE + * @static + * @final + */ +ParseError.FILE_TOO_LARGE = 129; + +/** + * Error code indicating an error saving a file. + * @property FILE_SAVE_ERROR + * @static + * @final + */ +ParseError.FILE_SAVE_ERROR = 130; + +/** + * Error code indicating that a unique field was given a value that is + * already taken. + * @property DUPLICATE_VALUE + * @static + * @final + */ +ParseError.DUPLICATE_VALUE = 137; + +/** + * Error code indicating that a role's name is invalid. + * @property INVALID_ROLE_NAME + * @static + * @final + */ +ParseError.INVALID_ROLE_NAME = 139; + +/** + * Error code indicating that an application quota was exceeded. Upgrade to + * resolve. + * @property EXCEEDED_QUOTA + * @static + * @final + */ +ParseError.EXCEEDED_QUOTA = 140; + +/** + * Error code indicating that a Cloud Code script failed. + * @property SCRIPT_FAILED + * @static + * @final + */ +ParseError.SCRIPT_FAILED = 141; + +/** + * Error code indicating that a Cloud Code validation failed. + * @property VALIDATION_ERROR + * @static + * @final + */ +ParseError.VALIDATION_ERROR = 142; + +/** + * Error code indicating that invalid image data was provided. + * @property INVALID_IMAGE_DATA + * @static + * @final + */ +ParseError.INVALID_IMAGE_DATA = 143; + +/** + * Error code indicating an unsaved file. + * @property UNSAVED_FILE_ERROR + * @static + * @final + */ +ParseError.UNSAVED_FILE_ERROR = 151; + +/** + * Error code indicating an invalid push time. + * @property INVALID_PUSH_TIME_ERROR + * @static + * @final + */ +ParseError.INVALID_PUSH_TIME_ERROR = 152; + +/** + * Error code indicating an error deleting a file. + * @property FILE_DELETE_ERROR + * @static + * @final + */ +ParseError.FILE_DELETE_ERROR = 153; + +/** + * Error code indicating that the application has exceeded its request + * limit. + * @property REQUEST_LIMIT_EXCEEDED + * @static + * @final + */ +ParseError.REQUEST_LIMIT_EXCEEDED = 155; + +/** + * Error code indicating an invalid event name. + * @property INVALID_EVENT_NAME + * @static + * @final + */ +ParseError.INVALID_EVENT_NAME = 160; + +/** + * Error code indicating that the username is missing or empty. + * @property USERNAME_MISSING + * @static + * @final + */ +ParseError.USERNAME_MISSING = 200; + +/** + * Error code indicating that the password is missing or empty. + * @property PASSWORD_MISSING + * @static + * @final + */ +ParseError.PASSWORD_MISSING = 201; + +/** + * Error code indicating that the username has already been taken. + * @property USERNAME_TAKEN + * @static + * @final + */ +ParseError.USERNAME_TAKEN = 202; + +/** + * Error code indicating that the email has already been taken. + * @property EMAIL_TAKEN + * @static + * @final + */ +ParseError.EMAIL_TAKEN = 203; + +/** + * Error code indicating that the email is missing, but must be specified. + * @property EMAIL_MISSING + * @static + * @final + */ +ParseError.EMAIL_MISSING = 204; + +/** + * Error code indicating that a user with the specified email was not found. + * @property EMAIL_NOT_FOUND + * @static + * @final + */ +ParseError.EMAIL_NOT_FOUND = 205; + +/** + * Error code indicating that a user object without a valid session could + * not be altered. + * @property SESSION_MISSING + * @static + * @final + */ +ParseError.SESSION_MISSING = 206; + +/** + * Error code indicating that a user can only be created through signup. + * @property MUST_CREATE_USER_THROUGH_SIGNUP + * @static + * @final + */ +ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; + +/** + * Error code indicating that an an account being linked is already linked + * to another user. + * @property ACCOUNT_ALREADY_LINKED + * @static + * @final + */ +ParseError.ACCOUNT_ALREADY_LINKED = 208; + +/** + * Error code indicating that the current session token is invalid. + * @property INVALID_SESSION_TOKEN + * @static + * @final + */ +ParseError.INVALID_SESSION_TOKEN = 209; + +/** + * Error code indicating that a user cannot be linked to an account because + * that account's id could not be found. + * @property LINKED_ID_MISSING + * @static + * @final + */ +ParseError.LINKED_ID_MISSING = 250; + +/** + * Error code indicating that a user with a linked (e.g. Facebook) account + * has an invalid session. + * @property INVALID_LINKED_SESSION + * @static + * @final + */ +ParseError.INVALID_LINKED_SESSION = 251; + +/** + * Error code indicating that a service being linked (e.g. Facebook or + * Twitter) is unsupported. + * @property UNSUPPORTED_SERVICE + * @static + * @final + */ +ParseError.UNSUPPORTED_SERVICE = 252; + +/** + * Error code indicating that there were multiple errors. Aggregate errors + * have an "errors" property, which is an array of error objects with more + * detail about each error that occurred. + * @property AGGREGATE_ERROR + * @static + * @final + */ +ParseError.AGGREGATE_ERROR = 600; + +/** + * Error code indicating the client was unable to read an input file. + * @property FILE_READ_ERROR + * @static + * @final + */ +ParseError.FILE_READ_ERROR = 601; + +/** + * Error code indicating a real error code is unavailable because + * we had to use an XDomainRequest object to allow CORS requests in + * Internet Explorer, which strips the body from HTTP responses that have + * a non-2XX status code. + * @property X_DOMAIN_REQUEST + * @static + * @final + */ +ParseError.X_DOMAIN_REQUEST = 602; \ No newline at end of file diff --git a/lib/node/ParseFile.js b/lib/node/ParseFile.js new file mode 100644 index 000000000..48efdb9d8 --- /dev/null +++ b/lib/node/ParseFile.js @@ -0,0 +1,291 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; + +function b64Digit(number) { + if (number < 26) { + return String.fromCharCode(65 + number); + } + if (number < 52) { + return String.fromCharCode(97 + (number - 26)); + } + if (number < 62) { + return String.fromCharCode(48 + (number - 52)); + } + if (number === 62) { + return '+'; + } + if (number === 63) { + return '/'; + } + throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); +} + +/** + * A Parse.File is a local representation of a file that is saved to the Parse + * cloud. + * @class Parse.File + * @constructor + * @param name {String} The file's name. This will be prefixed by a unique + * value once the file has finished saving. The file name must begin with + * an alphanumeric character, and consist of alphanumeric characters, + * periods, spaces, underscores, or dashes. + * @param data {Array} The data for the file, as either: + * 1. an Array of byte value Numbers, or + * 2. an Object like { base64: "..." } with a base64-encoded String. + * 3. a File object selected with a file upload control. (3) only works + * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. + * For example:
          + * var fileUploadControl = $("#profilePhotoFileUpload")[0];
          + * if (fileUploadControl.files.length > 0) {
          + *   var file = fileUploadControl.files[0];
          + *   var name = "photo.jpg";
          + *   var parseFile = new Parse.File(name, file);
          + *   parseFile.save().then(function() {
          + *     // The file has been saved to Parse.
          + *   }, function(error) {
          + *     // The file either could not be read, or could not be saved to Parse.
          + *   });
          + * }
          + * @param type {String} Optional Content-Type header to use for the file. If + * this is omitted, the content type will be inferred from the name's + * extension. + */ + +var ParseFile = function () { + function ParseFile(name, data, type) { + (0, _classCallCheck3.default)(this, ParseFile); + + var specifiedType = type || ''; + + this._name = name; + + if (data !== undefined) { + if (Array.isArray(data)) { + this._source = { + format: 'base64', + base64: ParseFile.encodeBase64(data), + type: specifiedType + }; + } else if (typeof File !== 'undefined' && data instanceof File) { + this._source = { + format: 'file', + file: data, + type: specifiedType + }; + } else if (data && typeof data.base64 === 'string') { + var _base = data.base64; + var commaIndex = _base.indexOf(','); + + if (commaIndex !== -1) { + var matches = dataUriRegexp.exec(_base.slice(0, commaIndex + 1)); + // if data URI with type and charset, there will be 4 matches. + this._source = { + format: 'base64', + base64: _base.slice(commaIndex + 1), + type: matches[1] + }; + } else { + this._source = { + format: 'base64', + base64: _base, + type: specifiedType + }; + } + } else { + throw new TypeError('Cannot create a Parse.File with that data.'); + } + } + } + + /** + * Gets the name of the file. Before save is called, this is the filename + * given by the user. After save is called, that name gets prefixed with a + * unique identifier. + * @method name + * @return {String} + */ + + (0, _createClass3.default)(ParseFile, [{ + key: 'name', + value: function () { + return this._name; + } + + /** + * Gets the url of the file. It is only available after you save the file or + * after you get the file from a Parse.Object. + * @method url + * @param {Object} options An object to specify url options + * @return {String} + */ + + }, { + key: 'url', + value: function (options) { + options = options || {}; + if (!this._url) { + return; + } + if (options.forceSecure) { + return this._url.replace(/^http:\/\//i, 'https://'); + } else { + return this._url; + } + } + + /** + * Saves the file to the Parse cloud. + * @method save + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} Promise that is resolved when the save finishes. + */ + + }, { + key: 'save', + value: function (options) { + var _this = this; + + options = options || {}; + var controller = _CoreManager2.default.getFileController(); + if (!this._previousSave) { + if (this._source.format === 'file') { + this._previousSave = controller.saveFile(this._name, this._source).then(function (res) { + _this._name = res.name; + _this._url = res.url; + return _this; + }); + } else { + this._previousSave = controller.saveBase64(this._name, this._source).then(function (res) { + _this._name = res.name; + _this._url = res.url; + return _this; + }); + } + } + if (this._previousSave) { + return this._previousSave._thenRunCallbacks(options); + } + } + }, { + key: 'toJSON', + value: function () { + return { + __type: 'File', + name: this._name, + url: this._url + }; + } + }, { + key: 'equals', + value: function (other) { + if (this === other) { + return true; + } + // Unsaved Files are never equal, since they will be saved to different URLs + return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; + } + }], [{ + key: 'fromJSON', + value: function (obj) { + if (obj.__type !== 'File') { + throw new TypeError('JSON object does not represent a ParseFile'); + } + var file = new ParseFile(obj.name); + file._url = obj.url; + return file; + } + }, { + key: 'encodeBase64', + value: function (bytes) { + var chunks = []; + chunks.length = Math.ceil(bytes.length / 3); + for (var i = 0; i < chunks.length; i++) { + var b1 = bytes[i * 3]; + var b2 = bytes[i * 3 + 1] || 0; + var b3 = bytes[i * 3 + 2] || 0; + + var has2 = i * 3 + 1 < bytes.length; + var has3 = i * 3 + 2 < bytes.length; + + chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); + } + + return chunks.join(''); + } + }]); + return ParseFile; +}(); + +exports.default = ParseFile; + +var DefaultController = { + saveFile: function (name, source) { + if (source.format !== 'file') { + throw new Error('saveFile can only be used with File-type sources.'); + } + // To directly upload a File, we use a REST-style AJAX request + var headers = { + 'X-Parse-Application-ID': _CoreManager2.default.get('APPLICATION_ID'), + 'X-Parse-JavaScript-Key': _CoreManager2.default.get('JAVASCRIPT_KEY'), + 'Content-Type': source.type || (source.file ? source.file.type : null) + }; + var url = _CoreManager2.default.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += 'files/' + name; + return _CoreManager2.default.getRESTController().ajax('POST', url, source.file, headers); + }, + + saveBase64: function (name, source) { + if (source.format !== 'base64') { + throw new Error('saveBase64 can only be used with Base64-type sources.'); + } + var data = { + base64: source.base64 + }; + if (source.type) { + data._ContentType = source.type; + } + + return _CoreManager2.default.getRESTController().request('POST', 'files/' + name, data); + } +}; + +_CoreManager2.default.setFileController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseGeoPoint.js b/lib/node/ParseGeoPoint.js new file mode 100644 index 000000000..98691f85b --- /dev/null +++ b/lib/node/ParseGeoPoint.js @@ -0,0 +1,235 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new GeoPoint with any of the following forms:
          + *
          + *   new GeoPoint(otherGeoPoint)
          + *   new GeoPoint(30, 30)
          + *   new GeoPoint([30, 30])
          + *   new GeoPoint({latitude: 30, longitude: 30})
          + *   new GeoPoint()  // defaults to (0, 0)
          + *   
          + * @class Parse.GeoPoint + * @constructor + * + *

          Represents a latitude / longitude point that may be associated + * with a key in a ParseObject or used as a reference point for geo queries. + * This allows proximity-based queries on the key.

          + * + *

          Only one key in a class may contain a GeoPoint.

          + * + *

          Example:

          + *   var point = new Parse.GeoPoint(30.0, -20.0);
          + *   var object = new Parse.Object("PlaceObject");
          + *   object.set("location", point);
          + *   object.save();

          + */ +var ParseGeoPoint = function () { + function ParseGeoPoint(arg1, arg2) { + (0, _classCallCheck3.default)(this, ParseGeoPoint); + + if (Array.isArray(arg1)) { + ParseGeoPoint._validate(arg1[0], arg1[1]); + this._latitude = arg1[0]; + this._longitude = arg1[1]; + } else if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { + ParseGeoPoint._validate(arg1.latitude, arg1.longitude); + this._latitude = arg1.latitude; + this._longitude = arg1.longitude; + } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { + ParseGeoPoint._validate(arg1, arg2); + this._latitude = arg1; + this._longitude = arg2; + } else { + this._latitude = 0; + this._longitude = 0; + } + } + + /** + * North-south portion of the coordinate, in range [-90, 90]. + * Throws an exception if set out of range in a modern browser. + * @property latitude + * @type Number + */ + + (0, _createClass3.default)(ParseGeoPoint, [{ + key: 'toJSON', + + /** + * Returns a JSON representation of the GeoPoint, suitable for Parse. + * @method toJSON + * @return {Object} + */ + value: function () { + ParseGeoPoint._validate(this._latitude, this._longitude); + return { + __type: 'GeoPoint', + latitude: this._latitude, + longitude: this._longitude + }; + } + }, { + key: 'equals', + value: function (other) { + return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; + } + + /** + * Returns the distance from this GeoPoint to another in radians. + * @method radiansTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'radiansTo', + value: function (point) { + var d2r = Math.PI / 180.0; + var lat1rad = this.latitude * d2r; + var long1rad = this.longitude * d2r; + var lat2rad = point.latitude * d2r; + var long2rad = point.longitude * d2r; + + var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); + var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); + // Square of half the straight line chord distance between both points. + var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; + a = Math.min(1.0, a); + return 2 * Math.asin(Math.sqrt(a)); + } + + /** + * Returns the distance from this GeoPoint to another in kilometers. + * @method kilometersTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'kilometersTo', + value: function (point) { + return this.radiansTo(point) * 6371.0; + } + + /** + * Returns the distance from this GeoPoint to another in miles. + * @method milesTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + + }, { + key: 'milesTo', + value: function (point) { + return this.radiansTo(point) * 3958.8; + } + + /** + * Throws an exception if the given lat-long is out of bounds. + */ + + }, { + key: 'latitude', + get: function () { + return this._latitude; + }, + set: function (val) { + ParseGeoPoint._validate(val, this.longitude); + this._latitude = val; + } + + /** + * East-west portion of the coordinate, in range [-180, 180]. + * Throws if set out of range in a modern browser. + * @property longitude + * @type Number + */ + + }, { + key: 'longitude', + get: function () { + return this._longitude; + }, + set: function (val) { + ParseGeoPoint._validate(this.latitude, val); + this._longitude = val; + } + }], [{ + key: '_validate', + value: function (latitude, longitude) { + if (latitude !== latitude || longitude !== longitude) { + throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); + } + if (latitude < -90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); + } + if (latitude > 90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); + } + if (longitude < -180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); + } + if (longitude > 180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); + } + } + + /** + * Creates a GeoPoint with the user's current location, if available. + * Calls options.success with a new GeoPoint instance or calls options.error. + * @method current + * @param {Object} options An object with success and error callbacks. + * @static + */ + + }, { + key: 'current', + value: function (options) { + var promise = new _ParsePromise2.default(); + navigator.geolocation.getCurrentPosition(function (location) { + promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); + }, function (error) { + promise.reject(error); + }); + + return promise._thenRunCallbacks(options); + } + }]); + return ParseGeoPoint; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseGeoPoint; \ No newline at end of file diff --git a/lib/node/ParseHooks.js b/lib/node/ParseHooks.js new file mode 100644 index 000000000..a2057e899 --- /dev/null +++ b/lib/node/ParseHooks.js @@ -0,0 +1,162 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _promise = require('babel-runtime/core-js/promise'); + +var _promise2 = _interopRequireDefault(_promise); + +exports.getFunctions = getFunctions; +exports.getTriggers = getTriggers; +exports.getFunction = getFunction; +exports.getTrigger = getTrigger; +exports.createFunction = createFunction; +exports.createTrigger = createTrigger; +exports.create = create; +exports.updateFunction = updateFunction; +exports.updateTrigger = updateTrigger; +exports.update = update; +exports.removeFunction = removeFunction; +exports.removeTrigger = removeTrigger; +exports.remove = remove; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function getFunctions() { + return _CoreManager2.default.getHooksController().get("functions"); +} + +function getTriggers() { + return _CoreManager2.default.getHooksController().get("triggers"); +} + +function getFunction(name) { + return _CoreManager2.default.getHooksController().get("functions", name); +} + +function getTrigger(className, triggerName) { + return _CoreManager2.default.getHooksController().get("triggers", className, triggerName); +} + +function createFunction(functionName, url) { + return create({ functionName: functionName, url: url }); +} + +function createTrigger(className, triggerName, url) { + return create({ className: className, triggerName: triggerName, url: url }); +} + +function create(hook) { + return _CoreManager2.default.getHooksController().create(hook); +} + +function updateFunction(functionName, url) { + return update({ functionName: functionName, url: url }); +} + +function updateTrigger(className, triggerName, url) { + return update({ className: className, triggerName: triggerName, url: url }); +} + +function update(hook) { + return _CoreManager2.default.getHooksController().update(hook); +} + +function removeFunction(functionName) { + return remove({ functionName: functionName }); +} + +function removeTrigger(className, triggerName) { + return remove({ className: className, triggerName: triggerName }); +} + +function remove(hook) { + return _CoreManager2.default.getHooksController().remove(hook); +} + +var DefaultController = { + get: function (type, functionName, triggerName) { + var url = "/hooks/" + type; + if (functionName) { + url += "/" + functionName; + if (triggerName) { + url += "/" + triggerName; + } + } + return this.sendRequest("GET", url); + }, + create: function (hook) { + var url; + if (hook.functionName && hook.url) { + url = "/hooks/functions"; + } else if (hook.className && hook.triggerName && hook.url) { + url = "/hooks/triggers"; + } else { + return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest("POST", url, hook); + }, + remove: function (hook) { + var url; + if (hook.functionName) { + url = "/hooks/functions/" + hook.functionName; + delete hook.functionName; + } else if (hook.className && hook.triggerName) { + url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; + delete hook.className; + delete hook.triggerName; + } else { + return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest("PUT", url, { "__op": "Delete" }); + }, + update: function (hook) { + var url; + if (hook.functionName && hook.url) { + url = "/hooks/functions/" + hook.functionName; + delete hook.functionName; + } else if (hook.className && hook.triggerName && hook.url) { + url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; + delete hook.className; + delete hook.triggerName; + } else { + return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest('PUT', url, hook); + }, + sendRequest: function (method, url, body) { + return _CoreManager2.default.getRESTController().request(method, url, body, { useMasterKey: true }).then(function (res) { + var decoded = (0, _decode2.default)(res); + if (decoded) { + return _ParsePromise2.default.as(decoded); + } + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); + }); + } +}; + +_CoreManager2.default.setHooksController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseInstallation.js b/lib/node/ParseInstallation.js new file mode 100644 index 000000000..02d7be1d8 --- /dev/null +++ b/lib/node/ParseInstallation.js @@ -0,0 +1,65 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var Installation = function (_ParseObject) { + (0, _inherits3.default)(Installation, _ParseObject); + + function Installation(attributes) { + (0, _classCallCheck3.default)(this, Installation); + + var _this = (0, _possibleConstructorReturn3.default)(this, (Installation.__proto__ || (0, _getPrototypeOf2.default)(Installation)).call(this, '_Installation')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + return _this; + } + + return Installation; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = Installation; + +_ParseObject3.default.registerSubclass('_Installation', Installation); \ No newline at end of file diff --git a/lib/node/ParseLiveQuery.js b/lib/node/ParseLiveQuery.js new file mode 100644 index 000000000..a3e5fe31d --- /dev/null +++ b/lib/node/ParseLiveQuery.js @@ -0,0 +1,241 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _EventEmitter = require('./EventEmitter'); + +var _EventEmitter2 = _interopRequireDefault(_EventEmitter); + +var _LiveQueryClient = require('./LiveQueryClient'); + +var _LiveQueryClient2 = _interopRequireDefault(_LiveQueryClient); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function open() { + var LiveQueryController = _CoreManager2.default.getLiveQueryController(); + LiveQueryController.open(); +} + +function close() { + var LiveQueryController = _CoreManager2.default.getLiveQueryController(); + LiveQueryController.close(); +} + +/** + * + * We expose three events to help you monitor the status of the WebSocket connection: + * + *

          Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

          + * Parse.LiveQuery.on('open', () => {
          + * 
          + * });

          + * + *

          Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

          + * Parse.LiveQuery.on('close', () => {
          + * 
          + * });

          + * + *

          Error - When some network error or LiveQuery server error happens, you'll get this event. + * + *

          + * Parse.LiveQuery.on('error', (error) => {
          + * 
          + * });

          + * + * @class Parse.LiveQuery + * @static + * + */ +var LiveQuery = new _EventEmitter2.default(); + +/** + * After open is called, the LiveQuery will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ +LiveQuery.open = open; + +/** + * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). + * This function will close the WebSocket connection to the LiveQuery server, + * cancel the auto reconnect, and unsubscribe all subscriptions based on it. + * If you call query.subscribe() after this, we'll create a new WebSocket + * connection to the LiveQuery server. + * + * @method close + */ + +LiveQuery.close = close; +// Register a default onError callback to make sure we do not crash on error +LiveQuery.on('error', function () {}); + +exports.default = LiveQuery; + +function getSessionToken() { + var controller = _CoreManager2.default.getUserController(); + return controller.currentUserAsync().then(function (currentUser) { + return currentUser ? currentUser.getSessionToken() : undefined; + }); +} + +function getLiveQueryClient() { + return _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient(); +} + +var defaultLiveQueryClient = void 0; +var DefaultLiveQueryController = { + setDefaultLiveQueryClient: function (liveQueryClient) { + defaultLiveQueryClient = liveQueryClient; + }, + getDefaultLiveQueryClient: function () { + if (defaultLiveQueryClient) { + return _ParsePromise2.default.as(defaultLiveQueryClient); + } + + return getSessionToken().then(function (sessionToken) { + var liveQueryServerURL = _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); + + if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL + if (!liveQueryServerURL) { + var tempServerURL = _CoreManager2.default.get('SERVER_URL'); + var protocol = 'ws://'; + // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix + if (tempServerURL.indexOf('https') === 0) { + protocol = 'wss://'; + } + var host = tempServerURL.replace(/^https?:\/\//, ''); + liveQueryServerURL = protocol + host; + _CoreManager2.default.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); + } + + var applicationId = _CoreManager2.default.get('APPLICATION_ID'); + var javascriptKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); + var masterKey = _CoreManager2.default.get('MASTER_KEY'); + // Get currentUser sessionToken if possible + defaultLiveQueryClient = new _LiveQueryClient2.default({ + applicationId: applicationId, + serverURL: liveQueryServerURL, + javascriptKey: javascriptKey, + masterKey: masterKey, + sessionToken: sessionToken + }); + // Register a default onError callback to make sure we do not crash on error + // Cannot create these events on a nested way because of EventEmiiter from React Native + defaultLiveQueryClient.on('error', function (error) { + LiveQuery.emit('error', error); + }); + defaultLiveQueryClient.on('open', function () { + LiveQuery.emit('open'); + }); + defaultLiveQueryClient.on('close', function () { + LiveQuery.emit('close'); + }); + + return defaultLiveQueryClient; + }); + }, + open: function () { + var _this = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this.resolve(liveQueryClient.open()); + }); + }, + close: function () { + var _this2 = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this2.resolve(liveQueryClient.close()); + }); + }, + subscribe: function (query) { + var _this3 = this; + + var subscriptionWrap = new _EventEmitter2.default(); + + getLiveQueryClient().then(function (liveQueryClient) { + if (liveQueryClient.shouldOpen()) { + liveQueryClient.open(); + } + var promiseSessionToken = getSessionToken(); + // new event emitter + return promiseSessionToken.then(function (sessionToken) { + + var subscription = liveQueryClient.subscribe(query, sessionToken); + // enter, leave create, etc + + subscriptionWrap.id = subscription.id; + subscriptionWrap.query = subscription.query; + subscriptionWrap.sessionToken = subscription.sessionToken; + subscriptionWrap.unsubscribe = subscription.unsubscribe; + // Cannot create these events on a nested way because of EventEmiiter from React Native + subscription.on('open', function () { + subscriptionWrap.emit('open'); + }); + subscription.on('create', function (object) { + subscriptionWrap.emit('create', object); + }); + subscription.on('update', function (object) { + subscriptionWrap.emit('update', object); + }); + subscription.on('enter', function (object) { + subscriptionWrap.emit('enter', object); + }); + subscription.on('leave', function (object) { + subscriptionWrap.emit('leave', object); + }); + subscription.on('delete', function (object) { + subscriptionWrap.emit('delete', object); + }); + + _this3.resolve(); + }); + }); + return subscriptionWrap; + }, + unsubscribe: function (subscription) { + var _this4 = this; + + getLiveQueryClient().then(function (liveQueryClient) { + _this4.resolve(liveQueryClient.unsubscribe(subscription)); + }); + }, + _clearCachedDefaultClient: function () { + defaultLiveQueryClient = null; + } +}; + +_CoreManager2.default.setLiveQueryController(DefaultLiveQueryController); \ No newline at end of file diff --git a/lib/node/ParseObject.js b/lib/node/ParseObject.js new file mode 100644 index 000000000..f08795e52 --- /dev/null +++ b/lib/node/ParseObject.js @@ -0,0 +1,2001 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _defineProperty = require('babel-runtime/core-js/object/define-property'); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +var _create = require('babel-runtime/core-js/object/create'); + +var _create2 = _interopRequireDefault(_create); + +var _freeze = require('babel-runtime/core-js/object/freeze'); + +var _freeze2 = _interopRequireDefault(_freeze); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _canBeSerialized = require('./canBeSerialized'); + +var _canBeSerialized2 = _interopRequireDefault(_canBeSerialized); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _equals = require('./equals'); + +var _equals2 = _interopRequireDefault(_equals); + +var _escape2 = require('./escape'); + +var _escape3 = _interopRequireDefault(_escape2); + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _parseDate = require('./parseDate'); + +var _parseDate2 = _interopRequireDefault(_parseDate); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseOp = require('./ParseOp'); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseQuery = require('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _SingleInstanceStateController = require('./SingleInstanceStateController'); + +var SingleInstanceStateController = _interopRequireWildcard(_SingleInstanceStateController); + +var _unique = require('./unique'); + +var _unique2 = _interopRequireDefault(_unique); + +var _UniqueInstanceStateController = require('./UniqueInstanceStateController'); + +var UniqueInstanceStateController = _interopRequireWildcard(_UniqueInstanceStateController); + +var _unsavedChildren = require('./unsavedChildren'); + +var _unsavedChildren2 = _interopRequireDefault(_unsavedChildren); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +// Mapping of class names to constructors, so we can populate objects from the +// server with appropriate subclasses of ParseObject +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var classMap = {}; + +// Global counter for generating unique local Ids +var localCount = 0; +// Global counter for generating unique Ids for non-single-instance objects +var objectCount = 0; +// On web clients, objects are single-instance: any two objects with the same Id +// will have the same attributes. However, this may be dangerous default +// behavior in a server scenario +var singleInstance = !_CoreManager2.default.get('IS_NODE'); +if (singleInstance) { + _CoreManager2.default.setObjectStateController(SingleInstanceStateController); +} else { + _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); +} + +function getServerUrlPath() { + var serverUrl = _CoreManager2.default.get('SERVER_URL'); + if (serverUrl[serverUrl.length - 1] !== '/') { + serverUrl += '/'; + } + var url = serverUrl.replace(/https?:\/\//, ''); + return url.substr(url.indexOf('/')); +} + +/** + * Creates a new model with defined attributes. + * + *

          You won't normally call this method directly. It is recommended that + * you use a subclass of Parse.Object instead, created by calling + * extend.

          + * + *

          However, if you don't want to use a subclass, or aren't sure which + * subclass is appropriate, you can use this form:

          + *     var object = new Parse.Object("ClassName");
          + * 
          + * That is basically equivalent to:
          + *     var MyClass = Parse.Object.extend("ClassName");
          + *     var object = new MyClass();
          + * 

          + * + * @class Parse.Object + * @constructor + * @param {String} className The class name for the object + * @param {Object} attributes The initial set of data to store in the object. + * @param {Object} options The options for this object instance. + */ + +var ParseObject = function () { + /** + * The ID of this object, unique within its class. + * @property id + * @type String + */ + function ParseObject(className, attributes, options) { + (0, _classCallCheck3.default)(this, ParseObject); + + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + var toSet = null; + this._objCount = objectCount++; + if (typeof className === 'string') { + this.className = className; + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + toSet = attributes; + } + } else if (className && (typeof className === 'undefined' ? 'undefined' : (0, _typeof3.default)(className)) === 'object') { + this.className = className.className; + toSet = {}; + for (var attr in className) { + if (attr !== 'className') { + toSet[attr] = className[attr]; + } + } + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + options = attributes; + } + } + if (toSet && !this.set(toSet, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + + /** Prototype getters / setters **/ + + (0, _createClass3.default)(ParseObject, [{ + key: '_getId', + + /** Private methods **/ + + /** + * Returns a local or server Id used uniquely identify this object + */ + value: function () { + if (typeof this.id === 'string') { + return this.id; + } + if (typeof this._localId === 'string') { + return this._localId; + } + var localId = 'local' + String(localCount++); + this._localId = localId; + return localId; + } + + /** + * Returns a unique identifier used to pull data from the State Controller. + */ + + }, { + key: '_getStateIdentifier', + value: function () { + if (singleInstance) { + var _id = this.id; + if (!_id) { + _id = this._getId(); + } + return { + id: _id, + className: this.className + }; + } else { + return this; + } + } + }, { + key: '_getServerData', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return stateController.getServerData(this._getStateIdentifier()); + } + }, { + key: '_clearServerData', + value: function () { + var serverData = this._getServerData(); + var unset = {}; + for (var attr in serverData) { + unset[attr] = undefined; + } + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.setServerData(this._getStateIdentifier(), unset); + } + }, { + key: '_getPendingOps', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return stateController.getPendingOps(this._getStateIdentifier()); + } + }, { + key: '_clearPendingOps', + value: function () { + var pending = this._getPendingOps(); + var latest = pending[pending.length - 1]; + var keys = (0, _keys2.default)(latest); + keys.forEach(function (key) { + delete latest[key]; + }); + } + }, { + key: '_getDirtyObjectAttributes', + value: function () { + var attributes = this.attributes; + var stateController = _CoreManager2.default.getObjectStateController(); + var objectCache = stateController.getObjectCache(this._getStateIdentifier()); + var dirty = {}; + for (var attr in attributes) { + var val = attributes[attr]; + if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof ParseObject) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { + // Due to the way browsers construct maps, the key order will not change + // unless the object is changed + try { + var json = (0, _encode2.default)(val, false, true); + var stringified = (0, _stringify2.default)(json); + if (objectCache[attr] !== stringified) { + dirty[attr] = val; + } + } catch (e) { + // Error occurred, possibly by a nested unsaved pointer in a mutable container + // No matter how it happened, it indicates a change in the attribute + dirty[attr] = val; + } + } + } + return dirty; + } + }, { + key: '_toFullJSON', + value: function (seen) { + var json = this.toJSON(seen); + json.__type = 'Object'; + json.className = this.className; + return json; + } + }, { + key: '_getSaveJSON', + value: function () { + var pending = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + var json = {}; + + for (var attr in dirtyObjects) { + json[attr] = new _ParseOp.SetOp(dirtyObjects[attr]).toJSON(); + } + for (attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + return json; + } + }, { + key: '_getSaveParams', + value: function () { + var method = this.id ? 'PUT' : 'POST'; + var body = this._getSaveJSON(); + var path = 'classes/' + this.className; + if (this.id) { + path += '/' + this.id; + } else if (this.className === '_User') { + path = 'users'; + } + return { + method: method, + body: body, + path: path + }; + } + }, { + key: '_finishFetch', + value: function (serverData) { + if (!this.id && serverData.objectId) { + this.id = serverData.objectId; + } + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.initializeState(this._getStateIdentifier()); + var decoded = {}; + for (var attr in serverData) { + if (attr === 'ACL') { + decoded[attr] = new _ParseACL2.default(serverData[attr]); + } else if (attr !== 'objectId') { + decoded[attr] = (0, _decode2.default)(serverData[attr]); + if (decoded[attr] instanceof _ParseRelation2.default) { + decoded[attr]._ensureParentAndKey(this, attr); + } + } + } + if (decoded.createdAt && typeof decoded.createdAt === 'string') { + decoded.createdAt = (0, _parseDate2.default)(decoded.createdAt); + } + if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { + decoded.updatedAt = (0, _parseDate2.default)(decoded.updatedAt); + } + if (!decoded.updatedAt && decoded.createdAt) { + decoded.updatedAt = decoded.createdAt; + } + stateController.commitServerChanges(this._getStateIdentifier(), decoded); + } + }, { + key: '_setExisted', + value: function (existed) { + var stateController = _CoreManager2.default.getObjectStateController(); + var state = stateController.getState(this._getStateIdentifier()); + if (state) { + state.existed = existed; + } + } + }, { + key: '_migrateId', + value: function (serverId) { + if (this._localId && serverId) { + if (singleInstance) { + var stateController = _CoreManager2.default.getObjectStateController(); + var oldState = stateController.removeState(this._getStateIdentifier()); + this.id = serverId; + delete this._localId; + if (oldState) { + stateController.initializeState(this._getStateIdentifier(), oldState); + } + } else { + this.id = serverId; + delete this._localId; + } + } + } + }, { + key: '_handleSaveResponse', + value: function (response, status) { + var changes = {}; + + var stateController = _CoreManager2.default.getObjectStateController(); + var pending = stateController.popPendingState(this._getStateIdentifier()); + for (var attr in pending) { + if (pending[attr] instanceof _ParseOp.RelationOp) { + changes[attr] = pending[attr].applyTo(undefined, this, attr); + } else if (!(attr in response)) { + // Only SetOps and UnsetOps should not come back with results + changes[attr] = pending[attr].applyTo(undefined); + } + } + for (attr in response) { + if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { + changes[attr] = (0, _parseDate2.default)(response[attr]); + } else if (attr === 'ACL') { + changes[attr] = new _ParseACL2.default(response[attr]); + } else if (attr !== 'objectId') { + changes[attr] = (0, _decode2.default)(response[attr]); + if (changes[attr] instanceof _ParseOp.UnsetOp) { + changes[attr] = undefined; + } + } + } + if (changes.createdAt && !changes.updatedAt) { + changes.updatedAt = changes.createdAt; + } + + this._migrateId(response.objectId); + + if (status !== 201) { + this._setExisted(true); + } + + stateController.commitServerChanges(this._getStateIdentifier(), changes); + } + }, { + key: '_handleSaveError', + value: function () { + this._getPendingOps(); + + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.mergeFirstPendingState(this._getStateIdentifier()); + } + + /** Public methods **/ + + }, { + key: 'initialize', + value: function () {} + // NOOP + + + /** + * Returns a JSON version of the object suitable for saving to Parse. + * @method toJSON + * @return {Object} + */ + + }, { + key: 'toJSON', + value: function (seen) { + var seenEntry = this.id ? this.className + ':' + this.id : this; + var seen = seen || [seenEntry]; + var json = {}; + var attrs = this.attributes; + for (var attr in attrs) { + if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { + json[attr] = attrs[attr].toJSON(); + } else { + json[attr] = (0, _encode2.default)(attrs[attr], false, false, seen); + } + } + var pending = this._getPendingOps(); + for (var attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + + if (this.id) { + json.objectId = this.id; + } + return json; + } + + /** + * Determines whether this ParseObject is equal to another ParseObject + * @method equals + * @return {Boolean} + */ + + }, { + key: 'equals', + value: function (other) { + if (this === other) { + return true; + } + return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; + } + + /** + * Returns true if this object has been modified since its last + * save/refresh. If an attribute is specified, it returns true only if that + * particular attribute has been modified since the last save/refresh. + * @method dirty + * @param {String} attr An attribute name (optional). + * @return {Boolean} + */ + + }, { + key: 'dirty', + value: function (attr) { + if (!this.id) { + return true; + } + var pendingOps = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + if (attr) { + if (dirtyObjects.hasOwnProperty(attr)) { + return true; + } + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i].hasOwnProperty(attr)) { + return true; + } + } + return false; + } + if ((0, _keys2.default)(pendingOps[0]).length !== 0) { + return true; + } + if ((0, _keys2.default)(dirtyObjects).length !== 0) { + return true; + } + return false; + } + + /** + * Returns an array of keys that have been modified since last save/refresh + * @method dirtyKeys + * @return {Array of string} + */ + + }, { + key: 'dirtyKeys', + value: function () { + var pendingOps = this._getPendingOps(); + var keys = {}; + for (var i = 0; i < pendingOps.length; i++) { + for (var attr in pendingOps[i]) { + keys[attr] = true; + } + } + var dirtyObjects = this._getDirtyObjectAttributes(); + for (var attr in dirtyObjects) { + keys[attr] = true; + } + return (0, _keys2.default)(keys); + } + + /** + * Gets a Pointer referencing this Object. + * @method toPointer + * @return {Object} + */ + + }, { + key: 'toPointer', + value: function () { + if (!this.id) { + throw new Error('Cannot create a pointer to an unsaved ParseObject'); + } + return { + __type: 'Pointer', + className: this.className, + objectId: this.id + }; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'get', + value: function (attr) { + return this.attributes[attr]; + } + + /** + * Gets a relation on the given class for the attribute. + * @method relation + * @param String attr The attribute to get the relation for. + */ + + }, { + key: 'relation', + value: function (attr) { + var value = this.get(attr); + if (value) { + if (!(value instanceof _ParseRelation2.default)) { + throw new Error('Called relation() on non-relation field ' + attr); + } + value._ensureParentAndKey(this, attr); + return value; + } + return new _ParseRelation2.default(this, attr); + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'escape', + value: function (attr) { + var val = this.attributes[attr]; + if (val == null) { + return ''; + } + + if (typeof val !== 'string') { + if (typeof val.toString !== 'function') { + return ''; + } + val = val.toString(); + } + return (0, _escape3.default)(val); + } + + /** + * Returns true if the attribute contains a value that is not + * null or undefined. + * @method has + * @param {String} attr The string name of the attribute. + * @return {Boolean} + */ + + }, { + key: 'has', + value: function (attr) { + var attributes = this.attributes; + if (attributes.hasOwnProperty(attr)) { + return attributes[attr] != null; + } + return false; + } + + /** + * Sets a hash of model attributes on the object. + * + *

          You can call it with an object containing keys and values, or with one + * key and value. For example:

          +     *   gameTurn.set({
          +     *     player: player1,
          +     *     diceRoll: 2
          +     *   }, {
          +     *     error: function(gameTurnAgain, error) {
          +     *       // The set failed validation.
          +     *     }
          +     *   });
          +     *
          +     *   game.set("currentPlayer", player2, {
          +     *     error: function(gameTurnAgain, error) {
          +     *       // The set failed validation.
          +     *     }
          +     *   });
          +     *
          +     *   game.set("finished", true);

          + * + * @method set + * @param {String} key The key to set. + * @param {} value The value to give it. + * @param {Object} options A set of options for the set. + * The only supported option is error. + * @return {Boolean} true if the set succeeded. + */ + + }, { + key: 'set', + value: function (key, value, options) { + var changes = {}; + var newOps = {}; + if (key && (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'object') { + changes = key; + options = value; + } else if (typeof key === 'string') { + changes[key] = value; + } else { + return this; + } + + options = options || {}; + var readonly = []; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var k in changes) { + if (k === 'createdAt' || k === 'updatedAt') { + // This property is read-only, but for legacy reasons we silently + // ignore it + continue; + } + if (readonly.indexOf(k) > -1) { + throw new Error('Cannot modify readonly attribute: ' + k); + } + if (options.unset) { + newOps[k] = new _ParseOp.UnsetOp(); + } else if (changes[k] instanceof _ParseOp.Op) { + newOps[k] = changes[k]; + } else if (changes[k] && (0, _typeof3.default)(changes[k]) === 'object' && typeof changes[k].__op === 'string') { + newOps[k] = (0, _ParseOp.opFromJSON)(changes[k]); + } else if (k === 'objectId' || k === 'id') { + if (typeof changes[k] === 'string') { + this.id = changes[k]; + } + } else if (k === 'ACL' && (0, _typeof3.default)(changes[k]) === 'object' && !(changes[k] instanceof _ParseACL2.default)) { + newOps[k] = new _ParseOp.SetOp(new _ParseACL2.default(changes[k])); + } else { + newOps[k] = new _ParseOp.SetOp(changes[k]); + } + } + + // Calculate new values + var currentAttributes = this.attributes; + var newValues = {}; + for (var attr in newOps) { + if (newOps[attr] instanceof _ParseOp.RelationOp) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); + } else if (!(newOps[attr] instanceof _ParseOp.UnsetOp)) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); + } + } + + // Validate changes + if (!options.ignoreValidation) { + var validation = this.validate(newValues); + if (validation) { + if (typeof options.error === 'function') { + options.error(this, validation); + } + return false; + } + } + + // Consolidate Ops + var pendingOps = this._getPendingOps(); + var last = pendingOps.length - 1; + var stateController = _CoreManager2.default.getObjectStateController(); + for (var attr in newOps) { + var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); + stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); + } + + return this; + } + + /** + * Remove an attribute from the model. This is a noop if the attribute doesn't + * exist. + * @method unset + * @param {String} attr The string name of an attribute. + */ + + }, { + key: 'unset', + value: function (attr, options) { + options = options || {}; + options.unset = true; + return this.set(attr, null, options); + } + + /** + * Atomically increments the value of the given attribute the next time the + * object is saved. If no amount is specified, 1 is used by default. + * + * @method increment + * @param attr {String} The key. + * @param amount {Number} The amount to increment by (optional). + */ + + }, { + key: 'increment', + value: function (attr, amount) { + if (typeof amount === 'undefined') { + amount = 1; + } + if (typeof amount !== 'number') { + throw new Error('Cannot increment by a non-numeric amount.'); + } + return this.set(attr, new _ParseOp.IncrementOp(amount)); + } + + /** + * Atomically add an object to the end of the array associated with a given + * key. + * @method add + * @param attr {String} The key. + * @param item {} The item to add. + */ + + }, { + key: 'add', + value: function (attr, item) { + return this.set(attr, new _ParseOp.AddOp([item])); + } + + /** + * Atomically add an object to the array associated with a given key, only + * if it is not already present in the array. The position of the insert is + * not guaranteed. + * + * @method addUnique + * @param attr {String} The key. + * @param item {} The object to add. + */ + + }, { + key: 'addUnique', + value: function (attr, item) { + return this.set(attr, new _ParseOp.AddUniqueOp([item])); + } + + /** + * Atomically remove all instances of an object from the array associated + * with a given key. + * + * @method remove + * @param attr {String} The key. + * @param item {} The object to remove. + */ + + }, { + key: 'remove', + value: function (attr, item) { + return this.set(attr, new _ParseOp.RemoveOp([item])); + } + + /** + * Returns an instance of a subclass of Parse.Op describing what kind of + * modification has been performed on this field since the last time it was + * saved. For example, after calling object.increment("x"), calling + * object.op("x") would return an instance of Parse.Op.Increment. + * + * @method op + * @param attr {String} The key. + * @returns {Parse.Op} The operation, or undefined if none. + */ + + }, { + key: 'op', + value: function (attr) { + var pending = this._getPendingOps(); + for (var i = pending.length; i--;) { + if (pending[i][attr]) { + return pending[i][attr]; + } + } + } + + /** + * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() + * @method clone + * @return {Parse.Object} + */ + + }, { + key: 'clone', + value: function () { + var clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + var attributes = this.attributes; + if (typeof this.constructor.readOnlyAttributes === 'function') { + var readonly = this.constructor.readOnlyAttributes() || []; + // Attributes are frozen, so we have to rebuild an object, + // rather than delete readonly keys + var copy = {}; + for (var a in attributes) { + if (readonly.indexOf(a) < 0) { + copy[a] = attributes[a]; + } + } + attributes = copy; + } + if (clone.set) { + clone.set(attributes); + } + return clone; + } + + /** + * Creates a new instance of this object. Not to be confused with clone() + * @method newInstance + * @return {Parse.Object} + */ + + }, { + key: 'newInstance', + value: function () { + var clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + clone.id = this.id; + if (singleInstance) { + // Just return an object with the right id + return clone; + } + + var stateController = _CoreManager2.default.getObjectStateController(); + if (stateController) { + stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); + } + return clone; + } + + /** + * Returns true if this object has never been saved to Parse. + * @method isNew + * @return {Boolean} + */ + + }, { + key: 'isNew', + value: function () { + return !this.id; + } + + /** + * Returns true if this object was created by the Parse server when the + * object might have already been there (e.g. in the case of a Facebook + * login) + * @method existed + * @return {Boolean} + */ + + }, { + key: 'existed', + value: function () { + if (!this.id) { + return false; + } + var stateController = _CoreManager2.default.getObjectStateController(); + var state = stateController.getState(this._getStateIdentifier()); + if (state) { + return state.existed; + } + return false; + } + + /** + * Checks if the model is currently in a valid state. + * @method isValid + * @return {Boolean} + */ + + }, { + key: 'isValid', + value: function () { + return !this.validate(this.attributes); + } + + /** + * You should not call this function directly unless you subclass + * Parse.Object, in which case you can override this method + * to provide additional validation on set and + * save. Your implementation should return + * + * @method validate + * @param {Object} attrs The current data to validate. + * @return {} False if the data is valid. An error object otherwise. + * @see Parse.Object#set + */ + + }, { + key: 'validate', + value: function (attrs) { + if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof _ParseACL2.default)) { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'ACL must be a Parse ACL.'); + } + for (var key in attrs) { + if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { + return new _ParseError2.default(_ParseError2.default.INVALID_KEY_NAME); + } + } + return false; + } + + /** + * Returns the ACL for this object. + * @method getACL + * @returns {Parse.ACL} An instance of Parse.ACL. + * @see Parse.Object#get + */ + + }, { + key: 'getACL', + value: function () { + var acl = this.get('ACL'); + if (acl instanceof _ParseACL2.default) { + return acl; + } + return null; + } + + /** + * Sets the ACL to be used for this object. + * @method setACL + * @param {Parse.ACL} acl An instance of Parse.ACL. + * @param {Object} options Optional Backbone-like options object to be + * passed in to set. + * @return {Boolean} Whether the set passed validation. + * @see Parse.Object#set + */ + + }, { + key: 'setACL', + value: function (acl, options) { + return this.set('ACL', acl, options); + } + + /** + * Clears any changes to this object made since the last call to save() + * @method revert + */ + + }, { + key: 'revert', + value: function () { + this._clearPendingOps(); + } + + /** + * Clears all attributes on a model + * @method clear + */ + + }, { + key: 'clear', + value: function () { + var attributes = this.attributes; + var erasable = {}; + var readonly = ['createdAt', 'updatedAt']; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var attr in attributes) { + if (readonly.indexOf(attr) < 0) { + erasable[attr] = true; + } + } + return this.set(erasable, { unset: true }); + } + + /** + * Fetch the model from the server. If the server's representation of the + * model differs from its current attributes, they will be overriden. + * + * @method fetch + * @param {Object} options A Backbone-style callback object. + * Valid options are:
            + *
          • success: A Backbone-style success callback. + *
          • error: An Backbone-style error callback. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * @return {Parse.Promise} A promise that is fulfilled when the fetch + * completes. + */ + + }, { + key: 'fetch', + value: function (options) { + options = options || {}; + var fetchOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + fetchOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + fetchOptions.sessionToken = options.sessionToken; + } + var controller = _CoreManager2.default.getObjectController(); + return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); + } + + /** + * Set a hash of model attributes, and save the model to the server. + * updatedAt will be updated when the request returns. + * You can either call it as:
          +     *   object.save();
          + * or
          +     *   object.save(null, options);
          + * or
          +     *   object.save(attrs, options);
          + * or
          +     *   object.save(key, value, options);
          + * + * For example,
          +     *   gameTurn.save({
          +     *     player: "Jake Cutter",
          +     *     diceRoll: 2
          +     *   }, {
          +     *     success: function(gameTurnAgain) {
          +     *       // The save was successful.
          +     *     },
          +     *     error: function(gameTurnAgain, error) {
          +     *       // The save failed.  Error is an instance of Parse.Error.
          +     *     }
          +     *   });
          + * or with promises:
          +     *   gameTurn.save({
          +     *     player: "Jake Cutter",
          +     *     diceRoll: 2
          +     *   }).then(function(gameTurnAgain) {
          +     *     // The save was successful.
          +     *   }, function(error) {
          +     *     // The save failed.  Error is an instance of Parse.Error.
          +     *   });
          + * + * @method save + * @param {Object} options A Backbone-style callback object. + * Valid options are:
            + *
          • success: A Backbone-style success callback. + *
          • error: An Backbone-style error callback. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * @return {Parse.Promise} A promise that is fulfilled when the save + * completes. + */ + + }, { + key: 'save', + value: function (arg1, arg2, arg3) { + var _this = this; + + var attrs; + var options; + if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object' || typeof arg1 === 'undefined') { + attrs = arg1; + if ((typeof arg2 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg2)) === 'object') { + options = arg2; + } + } else { + attrs = {}; + attrs[arg1] = arg2; + options = arg3; + } + + // Support save({ success: function() {}, error: function() {} }) + if (!options && attrs) { + options = {}; + if (typeof attrs.success === 'function') { + options.success = attrs.success; + delete attrs.success; + } + if (typeof attrs.error === 'function') { + options.error = attrs.error; + delete attrs.error; + } + } + + if (attrs) { + var validation = this.validate(attrs); + if (validation) { + if (options && typeof options.error === 'function') { + options.error(this, validation); + } + return _ParsePromise2.default.error(validation); + } + this.set(attrs, options); + } + + options = options || {}; + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = !!options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { + saveOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getObjectController(); + var unsaved = (0, _unsavedChildren2.default)(this); + return controller.save(unsaved, saveOptions).then(function () { + return controller.save(_this, saveOptions); + })._thenRunCallbacks(options, this); + } + + /** + * Destroy this model on the server if it was already persisted. + * If `wait: true` is passed, waits for the server to respond + * before removal. + * + * @method destroy + * @param {Object} options A Backbone-style callback object. + * Valid options are:
            + *
          • success: A Backbone-style success callback + *
          • error: An Backbone-style error callback. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * @return {Parse.Promise} A promise that is fulfilled when the destroy + * completes. + */ + + }, { + key: 'destroy', + value: function (options) { + options = options || {}; + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + if (!this.id) { + return _ParsePromise2.default.as()._thenRunCallbacks(options); + } + return _CoreManager2.default.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); + } + + /** Static methods **/ + + }, { + key: 'attributes', + get: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + return (0, _freeze2.default)(stateController.estimateAttributes(this._getStateIdentifier())); + } + + /** + * The first time this object was saved on the server. + * @property createdAt + * @type Date + */ + + }, { + key: 'createdAt', + get: function () { + return this._getServerData().createdAt; + } + + /** + * The last time this object was updated on the server. + * @property updatedAt + * @type Date + */ + + }, { + key: 'updatedAt', + get: function () { + return this._getServerData().updatedAt; + } + }], [{ + key: '_clearAllState', + value: function () { + var stateController = _CoreManager2.default.getObjectStateController(); + stateController.clearAllState(); + } + + /** + * Fetches the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
          +     *   Parse.Object.fetchAll([object1, object2, ...], {
          +     *     success: function(list) {
          +     *       // All the objects were fetched.
          +     *     },
          +     *     error: function(error) {
          +     *       // An error occurred while fetching one of the objects.
          +     *     },
          +     *   });
          +     * 
          + * + * @method fetchAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
            + *
          • success: A Backbone-style success callback. + *
          • error: An Backbone-style error callback. + *
          + */ + + }, { + key: 'fetchAll', + value: function (list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); + } + + /** + * Fetches the given list of Parse.Object if needed. + * If any error is encountered, stops and calls the error handler. + * + *
          +     *   Parse.Object.fetchAllIfNeeded([object1, ...], {
          +     *     success: function(list) {
          +     *       // Objects were fetched and updated.
          +     *     },
          +     *     error: function(error) {
          +     *       // An error occurred while fetching one of the objects.
          +     *     },
          +     *   });
          +     * 
          + * + * @method fetchAllIfNeeded + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
            + *
          • success: A Backbone-style success callback. + *
          • error: An Backbone-style error callback. + *
          + */ + + }, { + key: 'fetchAllIfNeeded', + value: function (list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); + } + + /** + * Destroy the given list of models on the server if it was already persisted. + * + *

          Unlike saveAll, if an error occurs while deleting an individual model, + * this method will continue trying to delete the rest of the models if + * possible, except in the case of a fatal error like a connection error. + * + *

          In particular, the Parse.Error object returned in the case of error may + * be one of two types: + * + *

            + *
          • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an + * array of other Parse.Error objects. Each error object in this array + * has an "object" property that references the object that could not be + * deleted (for instance, because that object could not be found).
          • + *
          • A non-aggregate Parse.Error. This indicates a serious error that + * caused the delete operation to be aborted partway through (for + * instance, a connection failure in the middle of the delete).
          • + *
          + * + *
          +     *   Parse.Object.destroyAll([object1, object2, ...], {
          +     *     success: function() {
          +     *       // All the objects were deleted.
          +     *     },
          +     *     error: function(error) {
          +     *       // An error occurred while deleting one or more of the objects.
          +     *       // If this is an aggregate error, then we can inspect each error
          +     *       // object individually to determine the reason why a particular
          +     *       // object was not deleted.
          +     *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
          +     *         for (var i = 0; i < error.errors.length; i++) {
          +     *           console.log("Couldn't delete " + error.errors[i].object.id +
          +     *             "due to " + error.errors[i].message);
          +     *         }
          +     *       } else {
          +     *         console.log("Delete aborted because of " + error.message);
          +     *       }
          +     *     },
          +     *   });
          +     * 
          + * + * @method destroyAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
            + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * @return {Parse.Promise} A promise that is fulfilled when the destroyAll + * completes. + */ + + }, { + key: 'destroyAll', + value: function (list, options) { + var options = options || {}; + + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); + } + + /** + * Saves the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
          +     *   Parse.Object.saveAll([object1, object2, ...], {
          +     *     success: function(list) {
          +     *       // All the objects were saved.
          +     *     },
          +     *     error: function(error) {
          +     *       // An error occurred while saving one of the objects.
          +     *     },
          +     *   });
          +     * 
          + * + * @method saveAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
            + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + */ + + }, { + key: 'saveAll', + value: function (list, options) { + var options = options || {}; + + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + saveOptions.sessionToken = options.sessionToken; + } + return _CoreManager2.default.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); + } + + /** + * Creates a reference to a subclass of Parse.Object with the given id. This + * does not exist on Parse.Object, only on subclasses. + * + *

          A shortcut for:

          +     *  var Foo = Parse.Object.extend("Foo");
          +     *  var pointerToFoo = new Foo();
          +     *  pointerToFoo.id = "myObjectId";
          +     * 
          + * + * @method createWithoutData + * @param {String} id The ID of the object to create a reference to. + * @static + * @return {Parse.Object} A Parse.Object reference. + */ + + }, { + key: 'createWithoutData', + value: function (id) { + var obj = new this(); + obj.id = id; + return obj; + } + + /** + * Creates a new instance of a Parse Object from a JSON representation. + * @method fromJSON + * @param {Object} json The JSON map of the Object's data + * @param {boolean} override In single instance mode, all old server data + * is overwritten if this is set to true + * @static + * @return {Parse.Object} A Parse.Object reference + */ + + }, { + key: 'fromJSON', + value: function (json, override) { + if (!json.className) { + throw new Error('Cannot create an object without a className'); + } + var constructor = classMap[json.className]; + var o = constructor ? new constructor() : new ParseObject(json.className); + var otherAttributes = {}; + for (var attr in json) { + if (attr !== 'className' && attr !== '__type') { + otherAttributes[attr] = json[attr]; + } + } + if (override) { + // id needs to be set before clearServerData can work + if (otherAttributes.objectId) { + o.id = otherAttributes.objectId; + } + var preserved = null; + if (typeof o._preserveFieldsOnFetch === 'function') { + preserved = o._preserveFieldsOnFetch(); + } + o._clearServerData(); + if (preserved) { + o._finishFetch(preserved); + } + } + o._finishFetch(otherAttributes); + if (json.objectId) { + o._setExisted(true); + } + return o; + } + + /** + * Registers a subclass of Parse.Object with a specific class name. + * When objects of that class are retrieved from a query, they will be + * instantiated with this subclass. + * This is only necessary when using ES6 subclassing. + * @method registerSubclass + * @param {String} className The class name of the subclass + * @param {Class} constructor The subclass + */ + + }, { + key: 'registerSubclass', + value: function (className, constructor) { + if (typeof className !== 'string') { + throw new TypeError('The first argument must be a valid class name.'); + } + if (typeof constructor === 'undefined') { + throw new TypeError('You must supply a subclass constructor.'); + } + if (typeof constructor !== 'function') { + throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); + } + classMap[className] = constructor; + if (!constructor.className) { + constructor.className = className; + } + } + + /** + * Creates a new subclass of Parse.Object for the given Parse class name. + * + *

          Every extension of a Parse class will inherit from the most recent + * previous extension of that class. When a Parse.Object is automatically + * created by parsing JSON, it will use the most recent extension of that + * class.

          + * + *

          You should call either:

          +     *     var MyClass = Parse.Object.extend("MyClass", {
          +     *         Instance methods,
          +     *         initialize: function(attrs, options) {
          +     *             this.someInstanceProperty = [],
          +     *             Other instance properties
          +     *         }
          +     *     }, {
          +     *         Class properties
          +     *     });
          + * or, for Backbone compatibility:
          +     *     var MyClass = Parse.Object.extend({
          +     *         className: "MyClass",
          +     *         Instance methods,
          +     *         initialize: function(attrs, options) {
          +     *             this.someInstanceProperty = [],
          +     *             Other instance properties
          +     *         }
          +     *     }, {
          +     *         Class properties
          +     *     });

          + * + * @method extend + * @param {String} className The name of the Parse class backing this model. + * @param {Object} protoProps Instance properties to add to instances of the + * class returned from this method. + * @param {Object} classProps Class properties to add the class returned from + * this method. + * @return {Class} A new subclass of Parse.Object. + */ + + }, { + key: 'extend', + value: function (className, protoProps, classProps) { + if (typeof className !== 'string') { + if (className && typeof className.className === 'string') { + return ParseObject.extend(className.className, className, protoProps); + } else { + throw new Error('Parse.Object.extend\'s first argument should be the className.'); + } + } + var adjustedClassName = className; + + if (adjustedClassName === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { + adjustedClassName = '_User'; + } + + var parentProto = ParseObject.prototype; + if (this.hasOwnProperty('__super__') && this.__super__) { + parentProto = this.prototype; + } else if (classMap[adjustedClassName]) { + parentProto = classMap[adjustedClassName].prototype; + } + var ParseObjectSubclass = function (attributes, options) { + this.className = adjustedClassName; + this._objCount = objectCount++; + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!this.set(attributes || {}, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + }; + ParseObjectSubclass.className = adjustedClassName; + ParseObjectSubclass.__super__ = parentProto; + + ParseObjectSubclass.prototype = (0, _create2.default)(parentProto, { + constructor: { + value: ParseObjectSubclass, + enumerable: false, + writable: true, + configurable: true + } + }); + + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseObjectSubclass.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseObjectSubclass, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + ParseObjectSubclass.extend = function (name, protoProps, classProps) { + if (typeof name === 'string') { + return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); + } + return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); + }; + ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; + + classMap[adjustedClassName] = ParseObjectSubclass; + return ParseObjectSubclass; + } + + /** + * Enable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * This is disabled by default in server environments, since it can lead to + * security issues. + * @method enableSingleInstance + */ + + }, { + key: 'enableSingleInstance', + value: function () { + singleInstance = true; + _CoreManager2.default.setObjectStateController(SingleInstanceStateController); + } + + /** + * Disable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * When disabled, you can have two instances of the same object in memory + * without them sharing attributes. + * @method disableSingleInstance + */ + + }, { + key: 'disableSingleInstance', + value: function () { + singleInstance = false; + _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); + } + }]); + return ParseObject; +}(); + +exports.default = ParseObject; + +var DefaultController = { + fetch: function (target, forceFetch, options) { + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + var objs = []; + var ids = []; + var className = null; + var results = []; + var error = null; + target.forEach(function (el, i) { + if (error) { + return; + } + if (!className) { + className = el.className; + } + if (className !== el.className) { + error = new _ParseError2.default(_ParseError2.default.INVALID_CLASS_NAME, 'All objects should be of the same class'); + } + if (!el.id) { + error = new _ParseError2.default(_ParseError2.default.MISSING_OBJECT_ID, 'All objects must have an ID'); + } + if (forceFetch || (0, _keys2.default)(el._getServerData()).length === 0) { + ids.push(el.id); + objs.push(el); + } + results.push(el); + }); + if (error) { + return _ParsePromise2.default.error(error); + } + var query = new _ParseQuery2.default(className); + query.containedIn('objectId', ids); + query._limit = ids.length; + return query.find(options).then(function (objects) { + var idMap = {}; + objects.forEach(function (o) { + idMap[o.id] = o; + }); + for (var i = 0; i < objs.length; i++) { + var obj = objs[i]; + if (!obj || !obj.id || !idMap[obj.id]) { + if (forceFetch) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); + } + } + } + if (!singleInstance) { + // If single instance objects are disabled, we need to replace the + for (var i = 0; i < results.length; i++) { + var obj = results[i]; + if (obj && obj.id && idMap[obj.id]) { + var id = obj.id; + obj._finishFetch(idMap[id].toJSON()); + results[i] = idMap[id]; + } + } + } + return _ParsePromise2.default.as(results); + }); + } else { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function (response, status, xhr) { + if (target instanceof ParseObject) { + target._clearPendingOps(); + target._clearServerData(); + target._finishFetch(response); + } + return target; + }); + } + }, + destroy: function (target, options) { + var RESTController = _CoreManager2.default.getRESTController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + var batches = [[]]; + target.forEach(function (obj) { + if (!obj.id) { + return; + } + batches[batches.length - 1].push(obj); + if (batches[batches.length - 1].length >= 20) { + batches.push([]); + } + }); + if (batches[batches.length - 1].length === 0) { + // If the last batch is empty, remove it + batches.pop(); + } + var deleteCompleted = _ParsePromise2.default.as(); + var errors = []; + batches.forEach(function (batch) { + deleteCompleted = deleteCompleted.then(function () { + return RESTController.request('POST', 'batch', { + requests: batch.map(function (obj) { + return { + method: 'DELETE', + path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), + body: {} + }; + }) + }, options).then(function (results) { + for (var i = 0; i < results.length; i++) { + if (results[i] && results[i].hasOwnProperty('error')) { + var err = new _ParseError2.default(results[i].error.code, results[i].error.error); + err.object = batch[i]; + errors.push(err); + } + } + }); + }); + }); + return deleteCompleted.then(function () { + if (errors.length) { + var aggregate = new _ParseError2.default(_ParseError2.default.AGGREGATE_ERROR); + aggregate.errors = errors; + return _ParsePromise2.default.error(aggregate); + } + return _ParsePromise2.default.as(target); + }); + } else if (target instanceof ParseObject) { + return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function () { + return _ParsePromise2.default.as(target); + }); + } + return _ParsePromise2.default.as(target); + }, + save: function (target, options) { + var RESTController = _CoreManager2.default.getRESTController(); + var stateController = _CoreManager2.default.getObjectStateController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return _ParsePromise2.default.as([]); + } + + var unsaved = target.concat(); + for (var i = 0; i < target.length; i++) { + if (target[i] instanceof ParseObject) { + unsaved = unsaved.concat((0, _unsavedChildren2.default)(target[i], true)); + } + } + unsaved = (0, _unique2.default)(unsaved); + + var filesSaved = _ParsePromise2.default.as(); + var pending = []; + unsaved.forEach(function (el) { + if (el instanceof _ParseFile2.default) { + filesSaved = filesSaved.then(function () { + return el.save(); + }); + } else if (el instanceof ParseObject) { + pending.push(el); + } + }); + + return filesSaved.then(function () { + var objectError = null; + return _ParsePromise2.default._continueWhile(function () { + return pending.length > 0; + }, function () { + var batch = []; + var nextPending = []; + pending.forEach(function (el) { + if (batch.length < 20 && (0, _canBeSerialized2.default)(el)) { + batch.push(el); + } else { + nextPending.push(el); + } + }); + pending = nextPending; + if (batch.length < 1) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); + } + + // Queue up tasks for each object in the batch. + // When every task is ready, the API request will execute + var batchReturned = new _ParsePromise2.default(); + var batchReady = []; + var batchTasks = []; + batch.forEach(function (obj, index) { + var ready = new _ParsePromise2.default(); + batchReady.push(ready); + + stateController.pushPendingState(obj._getStateIdentifier()); + batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { + ready.resolve(); + return batchReturned.then(function (responses, status) { + if (responses[index].hasOwnProperty('success')) { + obj._handleSaveResponse(responses[index].success, status); + } else { + if (!objectError && responses[index].hasOwnProperty('error')) { + var serverError = responses[index].error; + objectError = new _ParseError2.default(serverError.code, serverError.error); + // Cancel the rest of the save + pending = []; + } + obj._handleSaveError(); + } + }); + })); + }); + + _ParsePromise2.default.when(batchReady).then(function () { + // Kick off the batch request + return RESTController.request('POST', 'batch', { + requests: batch.map(function (obj) { + var params = obj._getSaveParams(); + params.path = getServerUrlPath() + params.path; + return params; + }) + }, options); + }).then(function (response, status, xhr) { + batchReturned.resolve(response, status); + }); + + return _ParsePromise2.default.when(batchTasks); + }).then(function () { + if (objectError) { + return _ParsePromise2.default.error(objectError); + } + return _ParsePromise2.default.as(target); + }); + }); + } else if (target instanceof ParseObject) { + // copying target lets Flow guarantee the pointer isn't modified elsewhere + var targetCopy = target; + var task = function () { + var params = targetCopy._getSaveParams(); + return RESTController.request(params.method, params.path, params.body, options).then(function (response, status) { + targetCopy._handleSaveResponse(response, status); + }, function (error) { + targetCopy._handleSaveError(); + return _ParsePromise2.default.error(error); + }); + }; + + stateController.pushPendingState(target._getStateIdentifier()); + return stateController.enqueueTask(target._getStateIdentifier(), task).then(function () { + return target; + }, function (error) { + return _ParsePromise2.default.error(error); + }); + } + return _ParsePromise2.default.as(); + } +}; + +_CoreManager2.default.setObjectController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseOp.js b/lib/node/ParseOp.js new file mode 100644 index 000000000..1eba19303 --- /dev/null +++ b/lib/node/ParseOp.js @@ -0,0 +1,579 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.RelationOp = exports.RemoveOp = exports.AddUniqueOp = exports.AddOp = exports.IncrementOp = exports.UnsetOp = exports.SetOp = exports.Op = undefined; + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +exports.opFromJSON = opFromJSON; + +var _arrayContainsObject = require('./arrayContainsObject'); + +var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); + +var _decode = require('./decode'); + +var _decode2 = _interopRequireDefault(_decode); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +var _unique = require('./unique'); + +var _unique2 = _interopRequireDefault(_unique); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function opFromJSON(json) { + if (!json || !json.__op) { + return null; + } + switch (json.__op) { + case 'Delete': + return new UnsetOp(); + case 'Increment': + return new IncrementOp(json.amount); + case 'Add': + return new AddOp((0, _decode2.default)(json.objects)); + case 'AddUnique': + return new AddUniqueOp((0, _decode2.default)(json.objects)); + case 'Remove': + return new RemoveOp((0, _decode2.default)(json.objects)); + case 'AddRelation': + var toAdd = (0, _decode2.default)(json.objects); + if (!Array.isArray(toAdd)) { + return new RelationOp([], []); + } + return new RelationOp(toAdd, []); + case 'RemoveRelation': + var toRemove = (0, _decode2.default)(json.objects); + if (!Array.isArray(toRemove)) { + return new RelationOp([], []); + } + return new RelationOp([], toRemove); + case 'Batch': + var toAdd = []; + var toRemove = []; + for (var i = 0; i < json.ops.length; i++) { + if (json.ops[i].__op === 'AddRelation') { + toAdd = toAdd.concat((0, _decode2.default)(json.ops[i].objects)); + } else if (json.ops[i].__op === 'RemoveRelation') { + toRemove = toRemove.concat((0, _decode2.default)(json.ops[i].objects)); + } + } + return new RelationOp(toAdd, toRemove); + } + return null; +} + +var Op = exports.Op = function () { + function Op() { + (0, _classCallCheck3.default)(this, Op); + } + + (0, _createClass3.default)(Op, [{ + key: 'applyTo', + + // Empty parent class + value: function (value) {} + }, { + key: 'mergeWith', + value: function (previous) {} + }, { + key: 'toJSON', + value: function () {} + }]); + return Op; +}(); + +var SetOp = exports.SetOp = function (_Op) { + (0, _inherits3.default)(SetOp, _Op); + + function SetOp(value) { + (0, _classCallCheck3.default)(this, SetOp); + + var _this = (0, _possibleConstructorReturn3.default)(this, (SetOp.__proto__ || (0, _getPrototypeOf2.default)(SetOp)).call(this)); + + _this._value = value; + return _this; + } + + (0, _createClass3.default)(SetOp, [{ + key: 'applyTo', + value: function (value) { + return this._value; + } + }, { + key: 'mergeWith', + value: function (previous) { + return new SetOp(this._value); + } + }, { + key: 'toJSON', + value: function () { + return (0, _encode2.default)(this._value, false, true); + } + }]); + return SetOp; +}(Op); + +var UnsetOp = exports.UnsetOp = function (_Op2) { + (0, _inherits3.default)(UnsetOp, _Op2); + + function UnsetOp() { + (0, _classCallCheck3.default)(this, UnsetOp); + return (0, _possibleConstructorReturn3.default)(this, (UnsetOp.__proto__ || (0, _getPrototypeOf2.default)(UnsetOp)).apply(this, arguments)); + } + + (0, _createClass3.default)(UnsetOp, [{ + key: 'applyTo', + value: function (value) { + return undefined; + } + }, { + key: 'mergeWith', + value: function (previous) { + return new UnsetOp(); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Delete' }; + } + }]); + return UnsetOp; +}(Op); + +var IncrementOp = exports.IncrementOp = function (_Op3) { + (0, _inherits3.default)(IncrementOp, _Op3); + + function IncrementOp(amount) { + (0, _classCallCheck3.default)(this, IncrementOp); + + var _this3 = (0, _possibleConstructorReturn3.default)(this, (IncrementOp.__proto__ || (0, _getPrototypeOf2.default)(IncrementOp)).call(this)); + + if (typeof amount !== 'number') { + throw new TypeError('Increment Op must be initialized with a numeric amount.'); + } + _this3._amount = amount; + return _this3; + } + + (0, _createClass3.default)(IncrementOp, [{ + key: 'applyTo', + value: function (value) { + if (typeof value === 'undefined') { + return this._amount; + } + if (typeof value !== 'number') { + throw new TypeError('Cannot increment a non-numeric value.'); + } + return this._amount + value; + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._amount); + } + if (previous instanceof IncrementOp) { + return new IncrementOp(this.applyTo(previous._amount)); + } + throw new Error('Cannot merge Increment Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Increment', amount: this._amount }; + } + }]); + return IncrementOp; +}(Op); + +var AddOp = exports.AddOp = function (_Op4) { + (0, _inherits3.default)(AddOp, _Op4); + + function AddOp(value) { + (0, _classCallCheck3.default)(this, AddOp); + + var _this4 = (0, _possibleConstructorReturn3.default)(this, (AddOp.__proto__ || (0, _getPrototypeOf2.default)(AddOp)).call(this)); + + _this4._value = Array.isArray(value) ? value : [value]; + return _this4; + } + + (0, _createClass3.default)(AddOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return this._value; + } + if (Array.isArray(value)) { + return value.concat(this._value); + } + throw new Error('Cannot add elements to a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddOp) { + return new AddOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge Add Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Add', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return AddOp; +}(Op); + +var AddUniqueOp = exports.AddUniqueOp = function (_Op5) { + (0, _inherits3.default)(AddUniqueOp, _Op5); + + function AddUniqueOp(value) { + (0, _classCallCheck3.default)(this, AddUniqueOp); + + var _this5 = (0, _possibleConstructorReturn3.default)(this, (AddUniqueOp.__proto__ || (0, _getPrototypeOf2.default)(AddUniqueOp)).call(this)); + + _this5._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); + return _this5; + } + + (0, _createClass3.default)(AddUniqueOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return this._value || []; + } + if (Array.isArray(value)) { + // copying value lets Flow guarantee the pointer isn't modified elsewhere + var valueCopy = value; + var toAdd = []; + this._value.forEach(function (v) { + if (v instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(valueCopy, v)) { + toAdd.push(v); + } + } else { + if (valueCopy.indexOf(v) < 0) { + toAdd.push(v); + } + } + }); + return value.concat(toAdd); + } + throw new Error('Cannot add elements to a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddUniqueOp) { + return new AddUniqueOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge AddUnique Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'AddUnique', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return AddUniqueOp; +}(Op); + +var RemoveOp = exports.RemoveOp = function (_Op6) { + (0, _inherits3.default)(RemoveOp, _Op6); + + function RemoveOp(value) { + (0, _classCallCheck3.default)(this, RemoveOp); + + var _this6 = (0, _possibleConstructorReturn3.default)(this, (RemoveOp.__proto__ || (0, _getPrototypeOf2.default)(RemoveOp)).call(this)); + + _this6._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); + return _this6; + } + + (0, _createClass3.default)(RemoveOp, [{ + key: 'applyTo', + value: function (value) { + if (value == null) { + return []; + } + if (Array.isArray(value)) { + var i = value.indexOf(this._value); + var removed = value.concat([]); + for (var i = 0; i < this._value.length; i++) { + var index = removed.indexOf(this._value[i]); + while (index > -1) { + removed.splice(index, 1); + index = removed.indexOf(this._value[i]); + } + if (this._value[i] instanceof _ParseObject2.default && this._value[i].id) { + for (var j = 0; j < removed.length; j++) { + if (removed[j] instanceof _ParseObject2.default && this._value[i].id === removed[j].id) { + removed.splice(j, 1); + j--; + } + } + } + } + return removed; + } + throw new Error('Cannot remove elements from a non-array value'); + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new UnsetOp(); + } + if (previous instanceof RemoveOp) { + var uniques = previous._value.concat([]); + for (var i = 0; i < this._value.length; i++) { + if (this._value[i] instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(uniques, this._value[i])) { + uniques.push(this._value[i]); + } + } else { + if (uniques.indexOf(this._value[i]) < 0) { + uniques.push(this._value[i]); + } + } + } + return new RemoveOp(uniques); + } + throw new Error('Cannot merge Remove Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + return { __op: 'Remove', objects: (0, _encode2.default)(this._value, false, true) }; + } + }]); + return RemoveOp; +}(Op); + +var RelationOp = exports.RelationOp = function (_Op7) { + (0, _inherits3.default)(RelationOp, _Op7); + + function RelationOp(adds, removes) { + (0, _classCallCheck3.default)(this, RelationOp); + + var _this7 = (0, _possibleConstructorReturn3.default)(this, (RelationOp.__proto__ || (0, _getPrototypeOf2.default)(RelationOp)).call(this)); + + _this7._targetClassName = null; + + if (Array.isArray(adds)) { + _this7.relationsToAdd = (0, _unique2.default)(adds.map(_this7._extractId, _this7)); + } + + if (Array.isArray(removes)) { + _this7.relationsToRemove = (0, _unique2.default)(removes.map(_this7._extractId, _this7)); + } + return _this7; + } + + (0, _createClass3.default)(RelationOp, [{ + key: '_extractId', + value: function (obj) { + if (typeof obj === 'string') { + return obj; + } + if (!obj.id) { + throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); + } + if (!this._targetClassName) { + this._targetClassName = obj.className; + } + if (this._targetClassName !== obj.className) { + throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); + } + return obj.id; + } + }, { + key: 'applyTo', + value: function (value, object, key) { + if (!value) { + if (!object || !key) { + throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); + } + var parent = new _ParseObject2.default(object.className); + if (object.id && object.id.indexOf('local') === 0) { + parent._localId = object.id; + } else if (object.id) { + parent.id = object.id; + } + var relation = new _ParseRelation2.default(parent, key); + relation.targetClassName = this._targetClassName; + return relation; + } + if (value instanceof _ParseRelation2.default) { + if (this._targetClassName) { + if (value.targetClassName) { + if (this._targetClassName !== value.targetClassName) { + throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); + } + } else { + value.targetClassName = this._targetClassName; + } + } + return value; + } else { + throw new Error('Relation cannot be applied to a non-relation field'); + } + } + }, { + key: 'mergeWith', + value: function (previous) { + if (!previous) { + return this; + } else if (previous instanceof UnsetOp) { + throw new Error('You cannot modify a relation after deleting it.'); + } else if (previous instanceof RelationOp) { + if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { + throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); + } + var newAdd = previous.relationsToAdd.concat([]); + this.relationsToRemove.forEach(function (r) { + var index = newAdd.indexOf(r); + if (index > -1) { + newAdd.splice(index, 1); + } + }); + this.relationsToAdd.forEach(function (r) { + var index = newAdd.indexOf(r); + if (index < 0) { + newAdd.push(r); + } + }); + + var newRemove = previous.relationsToRemove.concat([]); + this.relationsToAdd.forEach(function (r) { + var index = newRemove.indexOf(r); + if (index > -1) { + newRemove.splice(index, 1); + } + }); + this.relationsToRemove.forEach(function (r) { + var index = newRemove.indexOf(r); + if (index < 0) { + newRemove.push(r); + } + }); + + var newRelation = new RelationOp(newAdd, newRemove); + newRelation._targetClassName = this._targetClassName; + return newRelation; + } + throw new Error('Cannot merge Relation Op with the previous Op'); + } + }, { + key: 'toJSON', + value: function () { + var _this8 = this; + + var idToPointer = function (id) { + return { + __type: 'Pointer', + className: _this8._targetClassName, + objectId: id + }; + }; + + var adds = null; + var removes = null; + var pointers = null; + + if (this.relationsToAdd.length > 0) { + pointers = this.relationsToAdd.map(idToPointer); + adds = { __op: 'AddRelation', objects: pointers }; + } + if (this.relationsToRemove.length > 0) { + pointers = this.relationsToRemove.map(idToPointer); + removes = { __op: 'RemoveRelation', objects: pointers }; + } + + if (adds && removes) { + return { __op: 'Batch', ops: [adds, removes] }; + } + + return adds || removes || {}; + } + }]); + return RelationOp; +}(Op); \ No newline at end of file diff --git a/lib/node/ParsePromise.js b/lib/node/ParsePromise.js new file mode 100644 index 000000000..a79b4afee --- /dev/null +++ b/lib/node/ParsePromise.js @@ -0,0 +1,740 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getIterator2 = require('babel-runtime/core-js/get-iterator'); + +var _getIterator3 = _interopRequireDefault(_getIterator2); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var _isPromisesAPlusCompliant = true; + +/** + * A Promise is returned by async methods as a hook to provide callbacks to be + * called when the async task is fulfilled. + * + *

          Typical usage would be like:

          + *    query.find().then(function(results) {
          + *      results[0].set("foo", "bar");
          + *      return results[0].saveAsync();
          + *    }).then(function(result) {
          + *      console.log("Updated " + result.id);
          + *    });
          + * 

          + * + * @class Parse.Promise + * @constructor + */ + +var ParsePromise = function () { + function ParsePromise(executor) { + (0, _classCallCheck3.default)(this, ParsePromise); + + this._resolved = false; + this._rejected = false; + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + + if (typeof executor === 'function') { + executor(this.resolve.bind(this), this.reject.bind(this)); + } + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method resolve + * @param {Object} result the result to pass to the callbacks. + */ + + (0, _createClass3.default)(ParsePromise, [{ + key: 'resolve', + value: function () { + if (this._resolved || this._rejected) { + throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._resolved = true; + + for (var _len = arguments.length, results = Array(_len), _key = 0; _key < _len; _key++) { + results[_key] = arguments[_key]; + } + + this._result = results; + for (var i = 0; i < this._resolvedCallbacks.length; i++) { + this._resolvedCallbacks[i].apply(this, results); + } + + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method reject + * @param {Object} error the error to pass to the callbacks. + */ + + }, { + key: 'reject', + value: function (error) { + if (this._resolved || this._rejected) { + throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._rejected = true; + this._error = error; + for (var i = 0; i < this._rejectedCallbacks.length; i++) { + this._rejectedCallbacks[i](error); + } + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Adds callbacks to be called when this promise is fulfilled. Returns a new + * Promise that will be fulfilled when the callback is complete. It allows + * chaining. If the callback itself returns a Promise, then the one returned + * by "then" will not be fulfilled until that one returned by the callback + * is fulfilled. + * @method then + * @param {Function} resolvedCallback Function that is called when this + * Promise is resolved. Once the callback is complete, then the Promise + * returned by "then" will also be fulfilled. + * @param {Function} rejectedCallback Function that is called when this + * Promise is rejected with an error. Once the callback is complete, then + * the promise returned by "then" with be resolved successfully. If + * rejectedCallback is null, or it returns a rejected Promise, then the + * Promise returned by "then" will be rejected with that error. + * @return {Parse.Promise} A new Promise that will be fulfilled after this + * Promise is fulfilled and either callback has completed. If the callback + * returned a Promise, then this Promise will not be fulfilled until that + * one is. + */ + + }, { + key: 'then', + value: function (resolvedCallback, rejectedCallback) { + var _this = this; + + var promise = new ParsePromise(); + + var wrappedResolvedCallback = function () { + for (var _len2 = arguments.length, results = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + results[_key2] = arguments[_key2]; + } + + if (typeof resolvedCallback === 'function') { + if (_isPromisesAPlusCompliant) { + try { + results = [resolvedCallback.apply(this, results)]; + } catch (e) { + results = [ParsePromise.error(e)]; + } + } else { + results = [resolvedCallback.apply(this, results)]; + } + } + if (results.length === 1 && ParsePromise.is(results[0])) { + results[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + promise.resolve.apply(promise, results); + } + }; + + var wrappedRejectedCallback = function (error) { + var result = []; + if (typeof rejectedCallback === 'function') { + if (_isPromisesAPlusCompliant) { + try { + result = [rejectedCallback(error)]; + } catch (e) { + result = [ParsePromise.error(e)]; + } + } else { + result = [rejectedCallback(error)]; + } + if (result.length === 1 && ParsePromise.is(result[0])) { + result[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + if (_isPromisesAPlusCompliant) { + promise.resolve.apply(promise, result); + } else { + promise.reject(result[0]); + } + } + } else { + promise.reject(error); + } + }; + + var runLater = function (fn) { + fn.call(); + }; + if (_isPromisesAPlusCompliant) { + if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { + runLater = function (fn) { + process.nextTick(fn); + }; + } else if (typeof setTimeout === 'function') { + runLater = function (fn) { + setTimeout(fn, 0); + }; + } + } + + if (this._resolved) { + runLater(function () { + wrappedResolvedCallback.apply(_this, _this._result); + }); + } else if (this._rejected) { + runLater(function () { + wrappedRejectedCallback(_this._error); + }); + } else { + this._resolvedCallbacks.push(wrappedResolvedCallback); + this._rejectedCallbacks.push(wrappedRejectedCallback); + } + + return promise; + } + + /** + * Add handlers to be called when the promise + * is either resolved or rejected + * @method always + */ + + }, { + key: 'always', + value: function (callback) { + return this.then(callback, callback); + } + + /** + * Add handlers to be called when the Promise object is resolved + * @method done + */ + + }, { + key: 'done', + value: function (callback) { + return this.then(callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * Alias for catch(). + * @method fail + */ + + }, { + key: 'fail', + value: function (callback) { + return this.then(null, callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * @method catch + */ + + }, { + key: 'catch', + value: function (callback) { + return this.then(null, callback); + } + + /** + * Run the given callbacks after this promise is fulfilled. + * @method _thenRunCallbacks + * @param optionsOrCallback {} A Backbone-style options callback, or a + * callback function. If this is an options object and contains a "model" + * attributes, that will be passed to error callbacks as the first argument. + * @param model {} If truthy, this will be passed as the first result of + * error callbacks. This is for Backbone-compatability. + * @return {Parse.Promise} A promise that will be resolved after the + * callbacks are run, with the same result as this. + */ + + }, { + key: '_thenRunCallbacks', + value: function (optionsOrCallback, model) { + var options = {}; + if (typeof optionsOrCallback === 'function') { + options.success = function (result) { + optionsOrCallback(result, null); + }; + options.error = function (error) { + optionsOrCallback(null, error); + }; + } else if ((typeof optionsOrCallback === 'undefined' ? 'undefined' : (0, _typeof3.default)(optionsOrCallback)) === 'object') { + if (typeof optionsOrCallback.success === 'function') { + options.success = optionsOrCallback.success; + } + if (typeof optionsOrCallback.error === 'function') { + options.error = optionsOrCallback.error; + } + } + + return this.then(function () { + for (var _len3 = arguments.length, results = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + results[_key3] = arguments[_key3]; + } + + if (options.success) { + options.success.apply(this, results); + } + return ParsePromise.as.apply(ParsePromise, arguments); + }, function (error) { + if (options.error) { + if (typeof model !== 'undefined') { + options.error(model, error); + } else { + options.error(error); + } + } + // By explicitly returning a rejected Promise, this will work with + // either jQuery or Promises/A+ semantics. + return ParsePromise.error(error); + }); + } + + /** + * Adds a callback function that should be called regardless of whether + * this promise failed or succeeded. The callback will be given either the + * array of results for its first argument, or the error as its second, + * depending on whether this Promise was rejected or resolved. Returns a + * new Promise, like "then" would. + * @method _continueWith + * @param {Function} continuation the callback. + */ + + }, { + key: '_continueWith', + value: function (continuation) { + return this.then(function () { + for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + + return continuation(args, null); + }, function (error) { + return continuation(null, error); + }); + } + + /** + * Returns true iff the given object fulfils the Promise interface. + * @method is + * @param {Object} promise The object to test + * @static + * @return {Boolean} + */ + + }], [{ + key: 'is', + value: function (promise) { + return promise != null && typeof promise.then === 'function'; + } + + /** + * Returns a new promise that is resolved with a given value. + * @method as + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'as', + value: function () { + var promise = new ParsePromise(); + + for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + values[_key5] = arguments[_key5]; + } + + promise.resolve.apply(promise, values); + return promise; + } + + /** + * Returns a new promise that is resolved with a given value. + * If that value is a thenable Promise (has a .then() prototype + * method), the new promise will be chained to the end of the + * value. + * @method resolve + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'resolve', + value: function (value) { + return new ParsePromise(function (resolve, reject) { + if (ParsePromise.is(value)) { + value.then(resolve, reject); + } else { + resolve(value); + } + }); + } + + /** + * Returns a new promise that is rejected with a given error. + * @method error + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'error', + value: function () { + var promise = new ParsePromise(); + + for (var _len6 = arguments.length, errors = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + errors[_key6] = arguments[_key6]; + } + + promise.reject.apply(promise, errors); + return promise; + } + + /** + * Returns a new promise that is rejected with a given error. + * This is an alias for Parse.Promise.error, for compliance with + * the ES6 implementation. + * @method reject + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'reject', + value: function () { + for (var _len7 = arguments.length, errors = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + errors[_key7] = arguments[_key7]; + } + + return ParsePromise.error.apply(null, errors); + } + + /** + * Returns a new promise that is fulfilled when all of the input promises + * are resolved. If any promise in the list fails, then the returned promise + * will be rejected with an array containing the error from each promise. + * If they all succeed, then the returned promise will succeed, with the + * results being the results of all the input + * promises. For example:
          +     *   var p1 = Parse.Promise.as(1);
          +     *   var p2 = Parse.Promise.as(2);
          +     *   var p3 = Parse.Promise.as(3);
          +     *
          +     *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
          +     *     console.log(r1);  // prints 1
          +     *     console.log(r2);  // prints 2
          +     *     console.log(r3);  // prints 3
          +     *   });
          + * + * The input promises can also be specified as an array:
          +     *   var promises = [p1, p2, p3];
          +     *   Parse.Promise.when(promises).then(function(results) {
          +     *     console.log(results);  // prints [1,2,3]
          +     *   });
          +     * 
          + * @method when + * @param {Array} promises a list of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'when', + value: function (promises) { + var objects; + var arrayArgument = Array.isArray(promises); + if (arrayArgument) { + objects = promises; + } else { + objects = arguments; + } + + var total = objects.length; + var hadError = false; + var results = []; + var returnValue = arrayArgument ? [results] : results; + var errors = []; + results.length = objects.length; + errors.length = objects.length; + + if (total === 0) { + return ParsePromise.as.apply(this, returnValue); + } + + var promise = new ParsePromise(); + + var resolveOne = function () { + total--; + if (total <= 0) { + if (hadError) { + promise.reject(errors); + } else { + promise.resolve.apply(promise, returnValue); + } + } + }; + + var chain = function (object, index) { + if (ParsePromise.is(object)) { + object.then(function (result) { + results[index] = result; + resolveOne(); + }, function (error) { + errors[index] = error; + hadError = true; + resolveOne(); + }); + } else { + results[i] = object; + resolveOne(); + } + }; + for (var i = 0; i < objects.length; i++) { + chain(objects[i], i); + } + + return promise; + } + + /** + * Returns a new promise that is fulfilled when all of the promises in the + * iterable argument are resolved. If any promise in the list fails, then + * the returned promise will be immediately rejected with the reason that + * single promise rejected. If they all succeed, then the returned promise + * will succeed, with the results being the results of all the input + * promises. If the iterable provided is empty, the returned promise will + * be immediately resolved. + * + * For example:
          +     *   var p1 = Parse.Promise.as(1);
          +     *   var p2 = Parse.Promise.as(2);
          +     *   var p3 = Parse.Promise.as(3);
          +     *
          +     *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
          +     *     console.log(r1);  // prints 1
          +     *     console.log(r2);  // prints 2
          +     *     console.log(r3);  // prints 3
          +     *   });
          + * + * @method all + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'all', + value: function (promises) { + var total = 0; + var objects = []; + + var _iteratorNormalCompletion = true; + var _didIteratorError = false; + var _iteratorError = undefined; + + try { + for (var _iterator = (0, _getIterator3.default)(promises), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { + var p = _step.value; + + objects[total++] = p; + } + } catch (err) { + _didIteratorError = true; + _iteratorError = err; + } finally { + try { + if (!_iteratorNormalCompletion && _iterator.return) { + _iterator.return(); + } + } finally { + if (_didIteratorError) { + throw _iteratorError; + } + } + } + + if (total === 0) { + return ParsePromise.as([]); + } + + var hadError = false; + var promise = new ParsePromise(); + var resolved = 0; + var results = []; + objects.forEach(function (object, i) { + if (ParsePromise.is(object)) { + object.then(function (result) { + if (hadError) { + return false; + } + results[i] = result; + resolved++; + if (resolved >= total) { + promise.resolve(results); + } + }, function (error) { + // Reject immediately + promise.reject(error); + hadError = true; + }); + } else { + results[i] = object; + resolved++; + if (!hadError && resolved >= total) { + promise.resolve(results); + } + } + }); + + return promise; + } + + /** + * Returns a new promise that is immediately fulfilled when any of the + * promises in the iterable argument are resolved or rejected. If the + * first promise to complete is resolved, the returned promise will be + * resolved with the same value. Likewise, if the first promise to + * complete is rejected, the returned promise will be rejected with the + * same reason. + * + * @method race + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + + }, { + key: 'race', + value: function (promises) { + var completed = false; + var promise = new ParsePromise(); + var _iteratorNormalCompletion2 = true; + var _didIteratorError2 = false; + var _iteratorError2 = undefined; + + try { + for (var _iterator2 = (0, _getIterator3.default)(promises), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { + var p = _step2.value; + + if (ParsePromise.is(p)) { + p.then(function (result) { + if (completed) { + return; + } + completed = true; + promise.resolve(result); + }, function (error) { + if (completed) { + return; + } + completed = true; + promise.reject(error); + }); + } else if (!completed) { + completed = true; + promise.resolve(p); + } + } + } catch (err) { + _didIteratorError2 = true; + _iteratorError2 = err; + } finally { + try { + if (!_iteratorNormalCompletion2 && _iterator2.return) { + _iterator2.return(); + } + } finally { + if (_didIteratorError2) { + throw _iteratorError2; + } + } + } + + return promise; + } + + /** + * Runs the given asyncFunction repeatedly, as long as the predicate + * function returns a truthy value. Stops repeating if asyncFunction returns + * a rejected promise. + * @method _continueWhile + * @param {Function} predicate should return false when ready to stop. + * @param {Function} asyncFunction should return a Promise. + * @static + */ + + }, { + key: '_continueWhile', + value: function (predicate, asyncFunction) { + if (predicate()) { + return asyncFunction().then(function () { + return ParsePromise._continueWhile(predicate, asyncFunction); + }); + } + return ParsePromise.as(); + } + }, { + key: 'isPromisesAPlusCompliant', + value: function () { + return _isPromisesAPlusCompliant; + } + }, { + key: 'enableAPlusCompliant', + value: function () { + _isPromisesAPlusCompliant = true; + } + }, { + key: 'disableAPlusCompliant', + value: function () { + _isPromisesAPlusCompliant = false; + } + }]); + return ParsePromise; +}(); + +exports.default = ParsePromise; \ No newline at end of file diff --git a/lib/node/ParseQuery.js b/lib/node/ParseQuery.js new file mode 100644 index 000000000..664f5a737 --- /dev/null +++ b/lib/node/ParseQuery.js @@ -0,0 +1,1340 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _encode = require('./encode'); + +var _encode2 = _interopRequireDefault(_encode); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Converts a string into a regex that matches it. + * Surrounding with \Q .. \E does this, we just need to escape any \E's in + * the text separately. + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function quote(s) { + return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; +} + +/** + * Handles pre-populating the result data of a query with select fields, + * making sure that the data object contains keys for all objects that have + * been requested with a select, so that our cached state updates correctly. + */ +function handleSelectResult(data, select) { + var serverDataMask = {}; + + select.forEach(function (field) { + var hasSubObjectSelect = field.indexOf(".") !== -1; + if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { + // this field was selected, but is missing from the retrieved data + data[field] = undefined; + } else if (hasSubObjectSelect) { + // this field references a sub-object, + // so we need to walk down the path components + var pathComponents = field.split("."); + var obj = data; + var serverMask = serverDataMask; + + pathComponents.forEach(function (component, index, arr) { + // add keys if the expected data is missing + if (!obj[component]) { + obj[component] = index == arr.length - 1 ? undefined : {}; + } + obj = obj[component]; + + //add this path component to the server mask so we can fill it in later if needed + if (index < arr.length - 1) { + if (!serverMask[component]) { + serverMask[component] = {}; + } + } + }); + } + }); + + if ((0, _keys2.default)(serverDataMask).length > 0) { + var copyMissingDataWithMask = function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { + //copy missing elements at this level + if (copyThisLevel) { + for (var key in src) { + if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + } + for (var key in mask) { + //traverse into objects as needed + copyMissingDataWithMask(src[key], dest[key], mask[key], true); + } + }; + + // When selecting from sub-objects, we don't want to blow away the missing + // information that we may have retrieved before. We've already added any + // missing selected keys to sub-objects, but we still need to add in the + // data for any previously retrieved sub-objects that were not selected. + + var serverData = _CoreManager2.default.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); + + copyMissingDataWithMask(serverData, data, serverDataMask, false); + } +} + +/** + * Creates a new parse Parse.Query for the given Parse.Object subclass. + * @class Parse.Query + * @constructor + * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. + * + *

          Parse.Query defines a query that is used to fetch Parse.Objects. The + * most common use case is finding all objects that match a query through the + * find method. For example, this sample code fetches all objects + * of class MyClass. It calls a different function depending on + * whether the fetch succeeded or not. + * + *

          + * var query = new Parse.Query(MyClass);
          + * query.find({
          + *   success: function(results) {
          + *     // results is an array of Parse.Object.
          + *   },
          + *
          + *   error: function(error) {
          + *     // error is an instance of Parse.Error.
          + *   }
          + * });

          + * + *

          A Parse.Query can also be used to retrieve a single object whose id is + * known, through the get method. For example, this sample code fetches an + * object of class MyClass and id myId. It calls a + * different function depending on whether the fetch succeeded or not. + * + *

          + * var query = new Parse.Query(MyClass);
          + * query.get(myId, {
          + *   success: function(object) {
          + *     // object is an instance of Parse.Object.
          + *   },
          + *
          + *   error: function(object, error) {
          + *     // error is an instance of Parse.Error.
          + *   }
          + * });

          + * + *

          A Parse.Query can also be used to count the number of objects that match + * the query without retrieving all of those objects. For example, this + * sample code counts the number of objects of the class MyClass + *

          + * var query = new Parse.Query(MyClass);
          + * query.count({
          + *   success: function(number) {
          + *     // There are number instances of MyClass.
          + *   },
          + *
          + *   error: function(error) {
          + *     // error is an instance of Parse.Error.
          + *   }
          + * });

          + */ + +var ParseQuery = function () { + function ParseQuery(objectClass) { + (0, _classCallCheck3.default)(this, ParseQuery); + + if (typeof objectClass === 'string') { + if (objectClass === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { + this.className = '_User'; + } else { + this.className = objectClass; + } + } else if (objectClass instanceof _ParseObject2.default) { + this.className = objectClass.className; + } else if (typeof objectClass === 'function') { + if (typeof objectClass.className === 'string') { + this.className = objectClass.className; + } else { + var obj = new objectClass(); + this.className = obj.className; + } + } else { + throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); + } + + this._where = {}; + this._include = []; + this._limit = -1; // negative limit is not sent in the server request + this._skip = 0; + this._extraOptions = {}; + } + + /** + * Adds constraint that at least one of the passed in queries matches. + * @method _orQuery + * @param {Array} queries + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + (0, _createClass3.default)(ParseQuery, [{ + key: '_orQuery', + value: function (queries) { + var queryJSON = queries.map(function (q) { + return q.toJSON().where; + }); + + this._where.$or = queryJSON; + return this; + } + + /** + * Helper for condition queries + */ + + }, { + key: '_addCondition', + value: function (key, condition, value) { + if (!this._where[key] || typeof this._where[key] === 'string') { + this._where[key] = {}; + } + this._where[key][condition] = (0, _encode2.default)(value, false, true); + return this; + } + + /** + * Converts string for regular expression at the beginning + */ + + }, { + key: '_regexStartWith', + value: function (string) { + return '^' + quote(string); + } + + /** + * Returns a JSON representation of this query. + * @method toJSON + * @return {Object} The JSON representation of the query. + */ + + }, { + key: 'toJSON', + value: function () { + var params = { + where: this._where + }; + + if (this._include.length) { + params.include = this._include.join(','); + } + if (this._select) { + params.keys = this._select.join(','); + } + if (this._limit >= 0) { + params.limit = this._limit; + } + if (this._skip > 0) { + params.skip = this._skip; + } + if (this._order) { + params.order = this._order.join(','); + } + for (var key in this._extraOptions) { + params[key] = this._extraOptions[key]; + } + + return params; + } + + /** + * Constructs a Parse.Object whose id is already known by fetching data from + * the server. Either options.success or options.error is called when the + * find completes. + * + * @method get + * @param {String} objectId The id of the object to be fetched. + * @param {Object} options A Backbone-style options object. + * Valid options are:
            + *
          • success: A Backbone-style success callback + *
          • error: An Backbone-style error callback. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * + * @return {Parse.Promise} A promise that is resolved with the result when + * the query completes. + */ + + }, { + key: 'get', + value: function (objectId, options) { + this.equalTo('objectId', objectId); + + var firstOptions = {}; + if (options && options.hasOwnProperty('useMasterKey')) { + firstOptions.useMasterKey = options.useMasterKey; + } + if (options && options.hasOwnProperty('sessionToken')) { + firstOptions.sessionToken = options.sessionToken; + } + + return this.first(firstOptions).then(function (response) { + if (response) { + return response; + } + + var errorObject = new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'Object not found.'); + return _ParsePromise2.default.error(errorObject); + })._thenRunCallbacks(options, null); + } + + /** + * Retrieves a list of ParseObjects that satisfy this query. + * Either options.success or options.error is called when the find + * completes. + * + * @method find + * @param {Object} options A Backbone-style options object. Valid options + * are:
            + *
          • success: Function to call when the find completes successfully. + *
          • error: Function to call when the find fails. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * + * @return {Parse.Promise} A promise that is resolved with the results when + * the query completes. + */ + + }, { + key: 'find', + value: function (options) { + var _this2 = this; + + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var select = this._select; + + return controller.find(this.className, this.toJSON(), findOptions).then(function (response) { + return response.results.map(function (data) { + // In cases of relations, the server may send back a className + // on the top level of the payload + var override = response.className || _this2.className; + if (!data.className) { + data.className = override; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(data, select); + } + + return _ParseObject2.default.fromJSON(data, !select); + }); + })._thenRunCallbacks(options); + } + + /** + * Counts the number of objects that match this query. + * Either options.success or options.error is called when the count + * completes. + * + * @method count + * @param {Object} options A Backbone-style options object. Valid options + * are:
            + *
          • success: Function to call when the count completes successfully. + *
          • error: Function to call when the find fails. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * + * @return {Parse.Promise} A promise that is resolved with the count when + * the query completes. + */ + + }, { + key: 'count', + value: function (options) { + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var params = this.toJSON(); + params.limit = 0; + params.count = 1; + + return controller.find(this.className, params, findOptions).then(function (result) { + return result.count; + })._thenRunCallbacks(options); + } + + /** + * Retrieves at most one Parse.Object that satisfies this query. + * + * Either options.success or options.error is called when it completes. + * success is passed the object if there is one. otherwise, undefined. + * + * @method first + * @param {Object} options A Backbone-style options object. Valid options + * are:
            + *
          • success: Function to call when the find completes successfully. + *
          • error: Function to call when the find fails. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * + * @return {Parse.Promise} A promise that is resolved with the object when + * the query completes. + */ + + }, { + key: 'first', + value: function (options) { + var _this3 = this; + + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = _CoreManager2.default.getQueryController(); + + var params = this.toJSON(); + params.limit = 1; + + var select = this._select; + + return controller.find(this.className, params, findOptions).then(function (response) { + var objects = response.results; + if (!objects[0]) { + return undefined; + } + if (!objects[0].className) { + objects[0].className = _this3.className; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(objects[0], select); + } + + return _ParseObject2.default.fromJSON(objects[0], !select); + })._thenRunCallbacks(options); + } + + /** + * Iterates over each result of a query, calling a callback for each one. If + * the callback returns a promise, the iteration will not continue until + * that promise has been fulfilled. If the callback returns a rejected + * promise, then iteration will stop with that error. The items are + * processed in an unspecified order. The query may not have any sort order, + * and may not use limit or skip. + * @method each + * @param {Function} callback Callback that will be called with each result + * of the query. + * @param {Object} options A Backbone-style options object. Valid options + * are:
            + *
          • success: Function to call when the iteration completes successfully. + *
          • error: Function to call when the iteration fails. + *
          • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
          • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
          + * @return {Parse.Promise} A promise that will be fulfilled once the + * iteration has completed. + */ + + }, { + key: 'each', + value: function (callback, options) { + options = options || {}; + + if (this._order || this._skip || this._limit >= 0) { + return _ParsePromise2.default.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); + } + + new _ParsePromise2.default(); + + + var query = new ParseQuery(this.className); + // We can override the batch size from the options. + // This is undocumented, but useful for testing. + query._limit = options.batchSize || 100; + query._include = this._include.map(function (i) { + return i; + }); + if (this._select) { + query._select = this._select.map(function (s) { + return s; + }); + } + + query._where = {}; + for (var attr in this._where) { + var val = this._where[attr]; + if (Array.isArray(val)) { + query._where[attr] = val.map(function (v) { + return v; + }); + } else if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object') { + var conditionMap = {}; + query._where[attr] = conditionMap; + for (var cond in val) { + conditionMap[cond] = val[cond]; + } + } else { + query._where[attr] = val; + } + } + + query.ascending('objectId'); + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var finished = false; + return _ParsePromise2.default._continueWhile(function () { + return !finished; + }, function () { + return query.find(findOptions).then(function (results) { + var callbacksDone = _ParsePromise2.default.as(); + results.forEach(function (result) { + callbacksDone = callbacksDone.then(function () { + return callback(result); + }); + }); + + return callbacksDone.then(function () { + if (results.length >= query._limit) { + query.greaterThan('objectId', results[results.length - 1].id); + } else { + finished = true; + } + }); + }); + })._thenRunCallbacks(options); + } + + /** Query Conditions **/ + + /** + * Adds a constraint to the query that requires a particular key's value to + * be equal to the provided value. + * @method equalTo + * @param {String} key The key to check. + * @param value The value that the Parse.Object must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'equalTo', + value: function (key, value) { + if (typeof value === 'undefined') { + return this.doesNotExist(key); + } + + this._where[key] = (0, _encode2.default)(value, false, true); + return this; + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be not equal to the provided value. + * @method notEqualTo + * @param {String} key The key to check. + * @param value The value that must not be equalled. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'notEqualTo', + value: function (key, value) { + return this._addCondition(key, '$ne', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than the provided value. + * @method lessThan + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'lessThan', + value: function (key, value) { + return this._addCondition(key, '$lt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than the provided value. + * @method greaterThan + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'greaterThan', + value: function (key, value) { + return this._addCondition(key, '$gt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than or equal to the provided value. + * @method lessThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'lessThanOrEqualTo', + value: function (key, value) { + return this._addCondition(key, '$lte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than or equal to the provided value. + * @method greaterThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'greaterThanOrEqualTo', + value: function (key, value) { + return this._addCondition(key, '$gte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be contained in the provided list of values. + * @method containedIn + * @param {String} key The key to check. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containedIn', + value: function (key, value) { + return this._addCondition(key, '$in', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * not be contained in the provided list of values. + * @method notContainedIn + * @param {String} key The key to check. + * @param {Array} values The values that will not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'notContainedIn', + value: function (key, value) { + return this._addCondition(key, '$nin', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values. + * @method containsAll + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containsAll', + value: function (key, values) { + return this._addCondition(key, '$all', values); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values starting with given strings. + * @method containsAllStartingWith + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The string values that will match as starting string. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'containsAllStartingWith', + value: function (key, values) { + var _this = this; + if (!Array.isArray(values)) { + values = [values]; + } + + values = values.map(function (value) { + return { "$regex": _this._regexStartWith(value) }; + }); + + return this.containsAll(key, values); + } + + /** + * Adds a constraint for finding objects that contain the given key. + * @method exists + * @param {String} key The key that should exist. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'exists', + value: function (key) { + return this._addCondition(key, '$exists', true); + } + + /** + * Adds a constraint for finding objects that do not contain a given key. + * @method doesNotExist + * @param {String} key The key that should not exist + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotExist', + value: function (key) { + return this._addCondition(key, '$exists', false); + } + + /** + * Adds a regular expression constraint for finding string values that match + * the provided regular expression. + * This may be slow for large datasets. + * @method matches + * @param {String} key The key that the string to match is stored in. + * @param {RegExp} regex The regular expression pattern to match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matches', + value: function (key, regex, modifiers) { + this._addCondition(key, '$regex', regex); + if (!modifiers) { + modifiers = ''; + } + if (regex.ignoreCase) { + modifiers += 'i'; + } + if (regex.multiline) { + modifiers += 'm'; + } + if (modifiers.length) { + this._addCondition(key, '$options', modifiers); + } + return this; + } + + /** + * Adds a constraint that requires that a key's value matches a Parse.Query + * constraint. + * @method matchesQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matchesQuery', + value: function (key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$inQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value not matches a + * Parse.Query constraint. + * @method doesNotMatchQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotMatchQuery', + value: function (key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$notInQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value matches a value in + * an object returned by a different Parse.Query. + * @method matchesKeyInQuery + * @param {String} key The key that contains the value that is being + * matched. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'matchesKeyInQuery', + value: function (key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$select', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint that requires that a key's value not match a value in + * an object returned by a different Parse.Query. + * @method doesNotMatchKeyInQuery + * @param {String} key The key that contains the value that is being + * excluded. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'doesNotMatchKeyInQuery', + value: function (key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$dontSelect', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint for finding string values that contain a provided + * string. This may be slow for large datasets. + * @method contains + * @param {String} key The key that the string to match is stored in. + * @param {String} substring The substring that the value must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'contains', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value)); + } + + /** + * Adds a constraint for finding string values that start with a provided + * string. This query will use the backend index, so it will be fast even + * for large datasets. + * @method startsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} prefix The substring that the value must start with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'startsWith', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', this._regexStartWith(value)); + } + + /** + * Adds a constraint for finding string values that end with a provided + * string. This will be slow for large datasets. + * @method endsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} suffix The substring that the value must end with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'endsWith', + value: function (key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value) + '$'); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given. + * @method near + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'near', + value: function (key, point) { + if (!(point instanceof _ParseGeoPoint2.default)) { + // Try to cast it as a GeoPoint + point = new _ParseGeoPoint2.default(point); + } + return this._addCondition(key, '$nearSphere', point); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * @method withinRadians + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in radians) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinRadians', + value: function (key, point, distance) { + this.near(key, point); + return this._addCondition(key, '$maxDistance', distance); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 3958.8 miles. + * @method withinMiles + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in miles) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinMiles', + value: function (key, point, distance) { + return this.withinRadians(key, point, distance / 3958.8); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 6371.0 kilometers. + * @method withinKilometers + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in kilometers) of results + * to return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinKilometers', + value: function (key, point, distance) { + return this.withinRadians(key, point, distance / 6371.0); + } + + /** + * Adds a constraint to the query that requires a particular key's + * coordinates be contained within a given rectangular geographic bounding + * box. + * @method withinGeoBox + * @param {String} key The key to be constrained. + * @param {Parse.GeoPoint} southwest + * The lower-left inclusive corner of the box. + * @param {Parse.GeoPoint} northeast + * The upper-right inclusive corner of the box. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'withinGeoBox', + value: function (key, southwest, northeast) { + if (!(southwest instanceof _ParseGeoPoint2.default)) { + southwest = new _ParseGeoPoint2.default(southwest); + } + if (!(northeast instanceof _ParseGeoPoint2.default)) { + northeast = new _ParseGeoPoint2.default(northeast); + } + this._addCondition(key, '$within', { '$box': [southwest, northeast] }); + return this; + } + + /** Query Orderings **/ + + /** + * Sorts the results in ascending order by the given key. + * + * @method ascending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'ascending', + value: function () { + this._order = []; + + for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) { + keys[_key] = arguments[_key]; + } + + return this.addAscending.apply(this, keys); + } + + /** + * Sorts the results in ascending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addAscending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'addAscending', + value: function () { + var _this4 = this; + + if (!this._order) { + this._order = []; + } + + for (var _len2 = arguments.length, keys = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + keys[_key2] = arguments[_key2]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + key = key.join(); + } + _this4._order = _this4._order.concat(key.replace(/\s/g, '').split(',')); + }); + + return this; + } + + /** + * Sorts the results in descending order by the given key. + * + * @method descending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'descending', + value: function () { + this._order = []; + + for (var _len3 = arguments.length, keys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + keys[_key3] = arguments[_key3]; + } + + return this.addDescending.apply(this, keys); + } + + /** + * Sorts the results in descending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addDescending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'addDescending', + value: function () { + var _this5 = this; + + if (!this._order) { + this._order = []; + } + + for (var _len4 = arguments.length, keys = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + keys[_key4] = arguments[_key4]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + key = key.join(); + } + _this5._order = _this5._order.concat(key.replace(/\s/g, '').split(',').map(function (k) { + return '-' + k; + })); + }); + + return this; + } + + /** Query Options **/ + + /** + * Sets the number of results to skip before returning any results. + * This is useful for pagination. + * Default is to skip zero results. + * @method skip + * @param {Number} n the number of results to skip. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'skip', + value: function (n) { + if (typeof n !== 'number' || n < 0) { + throw new Error('You can only skip by a positive number'); + } + this._skip = n; + return this; + } + + /** + * Sets the limit of the number of results to return. The default limit is + * 100, with a maximum of 1000 results being returned at a time. + * @method limit + * @param {Number} n the number of results to limit to. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'limit', + value: function (n) { + if (typeof n !== 'number') { + throw new Error('You can only set the limit to a numeric value'); + } + this._limit = n; + return this; + } + + /** + * Includes nested Parse.Objects for the provided key. You can use dot + * notation to specify which fields in the included object are also fetched. + * @method include + * @param {String} key The name of the key to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'include', + value: function () { + var _this6 = this; + + for (var _len5 = arguments.length, keys = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + keys[_key5] = arguments[_key5]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + _this6._include = _this6._include.concat(key); + } else { + _this6._include.push(key); + } + }); + return this; + } + + /** + * Restricts the fields of the returned Parse.Objects to include only the + * provided keys. If this is called multiple times, then all of the keys + * specified in each of the calls will be included. + * @method select + * @param {Array} keys The names of the keys to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + + }, { + key: 'select', + value: function () { + var _this7 = this; + + if (!this._select) { + this._select = []; + } + + for (var _len6 = arguments.length, keys = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + keys[_key6] = arguments[_key6]; + } + + keys.forEach(function (key) { + if (Array.isArray(key)) { + _this7._select = _this7._select.concat(key); + } else { + _this7._select.push(key); + } + }); + return this; + } + + /** + * Subscribe this query to get liveQuery updates + * @method subscribe + * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter + * which can be used to get liveQuery updates. + */ + + }, { + key: 'subscribe', + value: function () { + var controller = _CoreManager2.default.getLiveQueryController(); + return controller.subscribe(this); + } + + /** + * Constructs a Parse.Query that is the OR of the passed in queries. For + * example: + *
          var compoundQuery = Parse.Query.or(query1, query2, query3);
          + * + * will create a compoundQuery that is an or of the query1, query2, and + * query3. + * @method or + * @param {...Parse.Query} var_args The list of queries to OR. + * @static + * @return {Parse.Query} The query that is the OR of the passed in queries. + */ + + }], [{ + key: 'or', + value: function () { + var className = null; + + for (var _len7 = arguments.length, queries = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + queries[_key7] = arguments[_key7]; + } + + queries.forEach(function (q) { + if (!className) { + className = q.className; + } + + if (className !== q.className) { + throw new Error('All queries must be for the same class.'); + } + }); + + var query = new ParseQuery(className); + query._orQuery(queries); + return query; + } + }]); + return ParseQuery; +}(); + +exports.default = ParseQuery; + +var DefaultController = { + find: function (className, params, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + return RESTController.request('GET', 'classes/' + className, params, options); + } +}; + +_CoreManager2.default.setQueryController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseRelation.js b/lib/node/ParseRelation.js new file mode 100644 index 000000000..fe9ea8769 --- /dev/null +++ b/lib/node/ParseRelation.js @@ -0,0 +1,182 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParseOp = require('./ParseOp'); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseQuery = require('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Creates a new Relation for the given parent object and key. This + * constructor should rarely be used directly, but rather created by + * Parse.Object.relation. + * @class Parse.Relation + * @constructor + * @param {Parse.Object} parent The parent of this relation. + * @param {String} key The key for this relation on the parent. + * + *

          + * A class that is used to access all of the children of a many-to-many + * relationship. Each instance of Parse.Relation is associated with a + * particular parent object and key. + *

          + */ +var ParseRelation = function () { + function ParseRelation(parent, key) { + (0, _classCallCheck3.default)(this, ParseRelation); + + this.parent = parent; + this.key = key; + this.targetClassName = null; + } + + /** + * Makes sure that this relation has the right parent and key. + */ + + (0, _createClass3.default)(ParseRelation, [{ + key: '_ensureParentAndKey', + value: function (parent, key) { + this.key = this.key || key; + if (this.key !== key) { + throw new Error('Internal Error. Relation retrieved from two different keys.'); + } + if (this.parent) { + if (this.parent.className !== parent.className) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + if (this.parent.id) { + if (this.parent.id !== parent.id) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + } else if (parent.id) { + this.parent = parent; + } + } else { + this.parent = parent; + } + } + + /** + * Adds a Parse.Object or an array of Parse.Objects to the relation. + * @method add + * @param {} objects The item or items to add. + */ + + }, { + key: 'add', + value: function (objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new _ParseOp.RelationOp(objects, []); + var parent = this.parent; + if (!parent) { + throw new Error('Cannot add to a Relation without a parent'); + } + parent.set(this.key, change); + this.targetClassName = change._targetClassName; + return parent; + } + + /** + * Removes a Parse.Object or an array of Parse.Objects from this relation. + * @method remove + * @param {} objects The item or items to remove. + */ + + }, { + key: 'remove', + value: function (objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new _ParseOp.RelationOp([], objects); + if (!this.parent) { + throw new Error('Cannot remove from a Relation without a parent'); + } + this.parent.set(this.key, change); + this.targetClassName = change._targetClassName; + } + + /** + * Returns a JSON version of the object suitable for saving to disk. + * @method toJSON + * @return {Object} + */ + + }, { + key: 'toJSON', + value: function () { + return { + __type: 'Relation', + className: this.targetClassName + }; + } + + /** + * Returns a Parse.Query that is limited to objects in this + * relation. + * @method query + * @return {Parse.Query} + */ + + }, { + key: 'query', + value: function () { + var query; + var parent = this.parent; + if (!parent) { + throw new Error('Cannot construct a query for a Relation without a parent'); + } + if (!this.targetClassName) { + query = new _ParseQuery2.default(parent.className); + query._extraOptions.redirectClassNameForKey = this.key; + } else { + query = new _ParseQuery2.default(this.targetClassName); + } + query._addCondition('$relatedTo', 'object', { + __type: 'Pointer', + className: parent.className, + objectId: parent.id + }); + query._addCondition('$relatedTo', 'key', this.key); + + return query; + } + }]); + return ParseRelation; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseRelation; \ No newline at end of file diff --git a/lib/node/ParseRole.js b/lib/node/ParseRole.js new file mode 100644 index 000000000..567af7a54 --- /dev/null +++ b/lib/node/ParseRole.js @@ -0,0 +1,196 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _get2 = require('babel-runtime/helpers/get'); + +var _get3 = _interopRequireDefault(_get2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Represents a Role on the Parse server. Roles represent groupings of + * Users for the purposes of granting permissions (e.g. specifying an ACL + * for an Object). Roles are specified by their sets of child users and + * child roles, all of which are granted any permissions that the parent + * role has. + * + *

          Roles must have a name (which cannot be changed after creation of the + * role), and must specify an ACL.

          + * @class Parse.Role + * @constructor + * @param {String} name The name of the Role to create. + * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. + * A Parse.Role is a local representation of a role persisted to the Parse + * cloud. + */ +var ParseRole = function (_ParseObject) { + (0, _inherits3.default)(ParseRole, _ParseObject); + + function ParseRole(name, acl) { + (0, _classCallCheck3.default)(this, ParseRole); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseRole.__proto__ || (0, _getPrototypeOf2.default)(ParseRole)).call(this, '_Role')); + + if (typeof name === 'string' && acl instanceof _ParseACL2.default) { + _this.setName(name); + _this.setACL(acl); + } + return _this; + } + + /** + * Gets the name of the role. You can alternatively call role.get("name") + * + * @method getName + * @return {String} the name of the role. + */ + + (0, _createClass3.default)(ParseRole, [{ + key: 'getName', + value: function () { + var name = this.get('name'); + if (name == null || typeof name === 'string') { + return name; + } + return ''; + } + + /** + * Sets the name for a role. This value must be set before the role has + * been saved to the server, and cannot be set once the role has been + * saved. + * + *

          + * A role's name can only contain alphanumeric characters, _, -, and + * spaces. + *

          + * + *

          This is equivalent to calling role.set("name", name)

          + * + * @method setName + * @param {String} name The name of the role. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + + }, { + key: 'setName', + value: function (name, options) { + return this.set('name', name, options); + } + + /** + * Gets the Parse.Relation for the Parse.Users that are direct + * children of this role. These users are granted any privileges that this + * role has been granted (e.g. read or write access through ACLs). You can + * add or remove users from the role through this relation. + * + *

          This is equivalent to calling role.relation("users")

          + * + * @method getUsers + * @return {Parse.Relation} the relation for the users belonging to this + * role. + */ + + }, { + key: 'getUsers', + value: function () { + return this.relation('users'); + } + + /** + * Gets the Parse.Relation for the Parse.Roles that are direct + * children of this role. These roles' users are granted any privileges that + * this role has been granted (e.g. read or write access through ACLs). You + * can add or remove child roles from this role through this relation. + * + *

          This is equivalent to calling role.relation("roles")

          + * + * @method getRoles + * @return {Parse.Relation} the relation for the roles belonging to this + * role. + */ + + }, { + key: 'getRoles', + value: function () { + return this.relation('roles'); + } + }, { + key: 'validate', + value: function (attrs, options) { + var isInvalid = (0, _get3.default)(ParseRole.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseRole.prototype), 'validate', this).call(this, attrs, options); + if (isInvalid) { + return isInvalid; + } + + if ('name' in attrs && attrs.name !== this.getName()) { + var newName = attrs.name; + if (this.id && this.id !== attrs.objectId) { + // Check to see if the objectId being set matches this.id + // This happens during a fetch -- the id is set before calling fetch + // Let the name be set in this case + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); + } + if (typeof newName !== 'string') { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name must be a String.'); + } + if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { + return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); + } + } + return false; + } + }]); + return ParseRole; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseRole; + +_ParseObject3.default.registerSubclass('_Role', ParseRole); \ No newline at end of file diff --git a/lib/node/ParseSession.js b/lib/node/ParseSession.js new file mode 100644 index 000000000..7fb75c80d --- /dev/null +++ b/lib/node/ParseSession.js @@ -0,0 +1,180 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _isRevocableSession = require('./isRevocableSession'); + +var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseUser = require('./ParseUser'); + +var _ParseUser2 = _interopRequireDefault(_ParseUser); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * @class Parse.Session + * @constructor + * + *

          A Parse.Session object is a local representation of a revocable session. + * This class is a subclass of a Parse.Object, and retains the same + * functionality of a Parse.Object.

          + */ +var ParseSession = function (_ParseObject) { + (0, _inherits3.default)(ParseSession, _ParseObject); + + function ParseSession(attributes) { + (0, _classCallCheck3.default)(this, ParseSession); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseSession.__proto__ || (0, _getPrototypeOf2.default)(ParseSession)).call(this, '_Session')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + return _this; + } + + /** + * Returns the session token string. + * @method getSessionToken + * @return {String} + */ + + (0, _createClass3.default)(ParseSession, [{ + key: 'getSessionToken', + value: function () { + var token = this.get('sessionToken'); + if (typeof token === 'string') { + return token; + } + return ''; + } + }], [{ + key: 'readOnlyAttributes', + value: function () { + return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; + } + + /** + * Retrieves the Session object for the currently logged in session. + * @method current + * @static + * @return {Parse.Promise} A promise that is resolved with the Parse.Session + * object after it has been fetched. If there is no current user, the + * promise will be rejected. + */ + + }, { + key: 'current', + value: function (options) { + options = options || {}; + var controller = _CoreManager2.default.getSessionController(); + + var sessionOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + sessionOptions.useMasterKey = options.useMasterKey; + } + return _ParseUser2.default.currentAsync().then(function (user) { + if (!user) { + return _ParsePromise2.default.error('There is no current user.'); + } + user.getSessionToken(); + + sessionOptions.sessionToken = user.getSessionToken(); + return controller.getSession(sessionOptions); + }); + } + + /** + * Determines whether the current session token is revocable. + * This method is useful for migrating Express.js or Node.js web apps to + * use revocable sessions. If you are migrating an app that uses the Parse + * SDK in the browser only, please use Parse.User.enableRevocableSession() + * instead, so that sessions can be automatically upgraded. + * @method isCurrentSessionRevocable + * @static + * @return {Boolean} + */ + + }, { + key: 'isCurrentSessionRevocable', + value: function () { + var currentUser = _ParseUser2.default.current(); + if (currentUser) { + return (0, _isRevocableSession2.default)(currentUser.getSessionToken() || ''); + } + return false; + } + }]); + return ParseSession; +}(_ParseObject3.default); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +exports.default = ParseSession; + +_ParseObject3.default.registerSubclass('_Session', ParseSession); + +var DefaultController = { + getSession: function (options) { + var RESTController = _CoreManager2.default.getRESTController(); + var session = new ParseSession(); + + return RESTController.request('GET', 'sessions/me', {}, options).then(function (sessionData) { + session._finishFetch(sessionData); + session._setExisted(true); + return session; + }); + } +}; + +_CoreManager2.default.setSessionController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseUser.js b/lib/node/ParseUser.js new file mode 100644 index 000000000..f18f42820 --- /dev/null +++ b/lib/node/ParseUser.js @@ -0,0 +1,1150 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _defineProperty = require('babel-runtime/core-js/object/define-property'); + +var _defineProperty2 = _interopRequireDefault(_defineProperty); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); + +var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); + +var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); + +var _get2 = require('babel-runtime/helpers/get'); + +var _get3 = _interopRequireDefault(_get2); + +var _inherits2 = require('babel-runtime/helpers/inherits'); + +var _inherits3 = _interopRequireDefault(_inherits2); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _isRevocableSession = require('./isRevocableSession'); + +var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParseObject2 = require('./ParseObject'); + +var _ParseObject3 = _interopRequireDefault(_ParseObject2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _ParseSession = require('./ParseSession'); + +var _ParseSession2 = _interopRequireDefault(_ParseSession); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var CURRENT_USER_KEY = 'currentUser'; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var canUseCurrentUser = !_CoreManager2.default.get('IS_NODE'); +var currentUserCacheMatchesDisk = false; +var currentUserCache = null; + +var authProviders = {}; + +/** + * @class Parse.User + * @constructor + * + *

          A Parse.User object is a local representation of a user persisted to the + * Parse cloud. This class is a subclass of a Parse.Object, and retains the + * same functionality of a Parse.Object, but also extends it with various + * user specific methods, like authentication, signing up, and validation of + * uniqueness.

          + */ + +var ParseUser = function (_ParseObject) { + (0, _inherits3.default)(ParseUser, _ParseObject); + + function ParseUser(attributes) { + (0, _classCallCheck3.default)(this, ParseUser); + + var _this = (0, _possibleConstructorReturn3.default)(this, (ParseUser.__proto__ || (0, _getPrototypeOf2.default)(ParseUser)).call(this, '_User')); + + if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { + if (!_this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Parse User'); + } + } + return _this; + } + + /** + * Request a revocable session token to replace the older style of token. + * @method _upgradeToRevocableSession + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is resolved when the replacement + * token has been fetched. + */ + + (0, _createClass3.default)(ParseUser, [{ + key: '_upgradeToRevocableSession', + value: function (options) { + options = options || {}; + + var upgradeOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + upgradeOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); + } + + /** + * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can + * call linkWith on the user (even if it doesn't exist yet on the server). + * @method _linkWith + */ + + }, { + key: '_linkWith', + value: function (provider, options) { + var _this2 = this; + + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[provider]; + } else { + authType = provider.getAuthType(); + } + if (options && options.hasOwnProperty('authData')) { + var authData = this.get('authData') || {}; + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + throw new Error('Invalid type: authData field should be an object'); + } + authData[authType] = options.authData; + + var controller = _CoreManager2.default.getUserController(); + return controller.linkWith(this, authData)._thenRunCallbacks(options, this); + } else { + var promise = new _ParsePromise2.default(); + provider.authenticate({ + success: function (provider, result) { + var opts = {}; + opts.authData = result; + if (options.success) { + opts.success = options.success; + } + if (options.error) { + opts.error = options.error; + } + _this2._linkWith(provider, opts).then(function () { + promise.resolve(_this2); + }, function (error) { + promise.reject(error); + }); + }, + error: function (provider, _error) { + if (typeof options.error === 'function') { + options.error(_this2, _error); + } + promise.reject(_error); + } + }); + return promise; + } + } + + /** + * Synchronizes auth data for a provider (e.g. puts the access token in the + * right place to be used by the Facebook SDK). + * @method _synchronizeAuthData + */ + + }, { + key: '_synchronizeAuthData', + value: function (provider) { + if (!this.isCurrent() || !provider) { + return; + } + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[authType]; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData'); + if (!provider || !authData || (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + var success = provider.restoreAuthentication(authData[authType]); + if (!success) { + this._unlinkFrom(provider); + } + } + + /** + * Synchronizes authData for all providers. + * @method _synchronizeAllAuthData + */ + + }, { + key: '_synchronizeAllAuthData', + value: function () { + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + this._synchronizeAuthData(key); + } + } + + /** + * Removes null values from authData (which exist temporarily for + * unlinking) + * @method _cleanupAuthData + */ + + }, { + key: '_cleanupAuthData', + value: function () { + if (!this.isCurrent()) { + return; + } + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + if (!authData[key]) { + delete authData[key]; + } + } + } + + /** + * Unlinks a user from a service. + * @method _unlinkFrom + */ + + }, { + key: '_unlinkFrom', + value: function (provider, options) { + var _this3 = this; + + if (typeof provider === 'string') { + provider = authProviders[provider]; + } else { + provider.getAuthType(); + } + return this._linkWith(provider, { authData: null }).then(function () { + _this3._synchronizeAuthData(provider); + return _ParsePromise2.default.as(_this3); + })._thenRunCallbacks(options); + } + + /** + * Checks whether a user is linked to a service. + * @method _isLinked + */ + + }, { + key: '_isLinked', + value: function (provider) { + var authType; + if (typeof provider === 'string') { + authType = provider; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData') || {}; + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return false; + } + return !!authData[authType]; + } + + /** + * Deauthenticates all providers. + * @method _logOutWithAll + */ + + }, { + key: '_logOutWithAll', + value: function () { + var authData = this.get('authData'); + if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { + return; + } + + for (var key in authData) { + this._logOutWith(key); + } + } + + /** + * Deauthenticates a single provider (e.g. removing access tokens from the + * Facebook SDK). + * @method _logOutWith + */ + + }, { + key: '_logOutWith', + value: function (provider) { + if (!this.isCurrent()) { + return; + } + if (typeof provider === 'string') { + provider = authProviders[provider]; + } + if (provider && provider.deauthenticate) { + provider.deauthenticate(); + } + } + + /** + * Class instance method used to maintain specific keys when a fetch occurs. + * Used to ensure that the session token is not lost. + */ + + }, { + key: '_preserveFieldsOnFetch', + value: function () { + return { + sessionToken: this.get('sessionToken') + }; + } + + /** + * Returns true if current would return this user. + * @method isCurrent + * @return {Boolean} + */ + + }, { + key: 'isCurrent', + value: function () { + var current = ParseUser.current(); + return !!current && current.id === this.id; + } + + /** + * Returns get("username"). + * @method getUsername + * @return {String} + */ + + }, { + key: 'getUsername', + value: function () { + var username = this.get('username'); + if (username == null || typeof username === 'string') { + return username; + } + return ''; + } + + /** + * Calls set("username", username, options) and returns the result. + * @method setUsername + * @param {String} username + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setUsername', + value: function (username) { + // Strip anonymity, even we do not support anonymous user in js SDK, we may + // encounter anonymous user created by android/iOS in cloud code. + var authData = this.get('authData'); + if (authData && (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) === 'object' && authData.hasOwnProperty('anonymous')) { + // We need to set anonymous to null instead of deleting it in order to remove it from Parse. + authData.anonymous = null; + } + this.set('username', username); + } + + /** + * Calls set("password", password, options) and returns the result. + * @method setPassword + * @param {String} password + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setPassword', + value: function (password) { + this.set('password', password); + } + + /** + * Returns get("email"). + * @method getEmail + * @return {String} + */ + + }, { + key: 'getEmail', + value: function () { + var email = this.get('email'); + if (email == null || typeof email === 'string') { + return email; + } + return ''; + } + + /** + * Calls set("email", email, options) and returns the result. + * @method setEmail + * @param {String} email + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + + }, { + key: 'setEmail', + value: function (email) { + this.set('email', email); + } + + /** + * Returns the session token for this user, if the user has been logged in, + * or if it is the result of a query with the master key. Otherwise, returns + * undefined. + * @method getSessionToken + * @return {String} the session token, or undefined + */ + + }, { + key: 'getSessionToken', + value: function () { + var token = this.get('sessionToken'); + if (token == null || typeof token === 'string') { + return token; + } + return ''; + } + + /** + * Checks whether this user is the current user and has been authenticated. + * @method authenticated + * @return (Boolean) whether this user is the current user and is logged in. + */ + + }, { + key: 'authenticated', + value: function () { + var current = ParseUser.current(); + return !!this.get('sessionToken') && !!current && current.id === this.id; + } + + /** + * Signs up a new user. You should call this instead of save for + * new Parse.Users. This will create a new Parse.User on the server, and + * also persist the session on disk so that you can access the user using + * current. + * + *

          A username and password must be set before calling signUp.

          + * + *

          Calls options.success or options.error on completion.

          + * + * @method signUp + * @param {Object} attrs Extra fields to set on the new user, or null. + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled when the signup + * finishes. + */ + + }, { + key: 'signUp', + value: function (attrs, options) { + options = options || {}; + + var signupOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + signupOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + signupOptions.installationId = options.installationId; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); + } + + /** + * Logs in a Parse.User. On success, this saves the session to disk, + * so you can retrieve the currently logged in user using + * current. + * + *

          A username and password must be set before calling logIn.

          + * + *

          Calls options.success or options.error on completion.

          + * + * @method logIn + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login is complete. + */ + + }, { + key: 'logIn', + value: function (options) { + options = options || {}; + + var loginOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + loginOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + loginOptions.installationId = options.installationId; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); + } + + /** + * Wrap the default save behavior with functionality to save to local + * storage if this is current user. + */ + + }, { + key: 'save', + value: function () { + var _this4 = this; + + for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'save', this).apply(this, args).then(function () { + if (_this4.isCurrent()) { + return _CoreManager2.default.getUserController().updateUserOnDisk(_this4); + } + return _this4; + }); + } + + /** + * Wrap the default destroy behavior with functionality that logs out + * the current user when it is destroyed + */ + + }, { + key: 'destroy', + value: function () { + var _this5 = this; + + for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'destroy', this).apply(this, args).then(function () { + if (_this5.isCurrent()) { + return _CoreManager2.default.getUserController().removeUserFromDisk(); + } + return _this5; + }); + } + + /** + * Wrap the default fetch behavior with functionality to save to local + * storage if this is current user. + */ + + }, { + key: 'fetch', + value: function () { + var _this6 = this; + + for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + + return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'fetch', this).apply(this, args).then(function () { + if (_this6.isCurrent()) { + return _CoreManager2.default.getUserController().updateUserOnDisk(_this6); + } + return _this6; + }); + } + }], [{ + key: 'readOnlyAttributes', + value: function () { + return ['sessionToken']; + } + + /** + * Adds functionality to the existing Parse.User class + * @method extend + * @param {Object} protoProps A set of properties to add to the prototype + * @param {Object} classProps A set of static properties to add to the class + * @static + * @return {Class} The newly extended Parse.User class + */ + + }, { + key: 'extend', + value: function (protoProps, classProps) { + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseUser.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + (0, _defineProperty2.default)(ParseUser, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + return ParseUser; + } + + /** + * Retrieves the currently logged in ParseUser with a valid session, + * either from memory or localStorage, if necessary. + * @method current + * @static + * @return {Parse.Object} The currently logged in Parse.User. + */ + + }, { + key: 'current', + value: function () { + if (!canUseCurrentUser) { + return null; + } + var controller = _CoreManager2.default.getUserController(); + return controller.currentUser(); + } + + /** + * Retrieves the currently logged in ParseUser from asynchronous Storage. + * @method currentAsync + * @static + * @return {Parse.Promise} A Promise that is resolved with the currently + * logged in Parse User + */ + + }, { + key: 'currentAsync', + value: function () { + if (!canUseCurrentUser) { + return _ParsePromise2.default.as(null); + } + var controller = _CoreManager2.default.getUserController(); + return controller.currentUserAsync(); + } + + /** + * Signs up a new user with a username (or email) and password. + * This will create a new Parse.User on the server, and also persist the + * session in localStorage so that you can access the user using + * {@link #current}. + * + *

          Calls options.success or options.error on completion.

          + * + * @method signUp + * @param {String} username The username (or email) to sign up with. + * @param {String} password The password to sign up with. + * @param {Object} attrs Extra fields to set on the new user. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the signup completes. + */ + + }, { + key: 'signUp', + value: function (username, password, attrs, options) { + attrs = attrs || {}; + attrs.username = username; + attrs.password = password; + var user = new ParseUser(attrs); + return user.signUp({}, options); + } + + /** + * Logs in a user with a username (or email) and password. On success, this + * saves the session to disk, so you can retrieve the currently logged in + * user using current. + * + *

          Calls options.success or options.error on completion.

          + * + * @method logIn + * @param {String} username The username (or email) to log in with. + * @param {String} password The password to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + + }, { + key: 'logIn', + value: function (username, password, options) { + if (typeof username !== 'string') { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Username must be a string.')); + } else if (typeof password !== 'string') { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Password must be a string.')); + } + var user = new ParseUser(); + user._finishFetch({ username: username, password: password }); + return user.logIn(options); + } + + /** + * Logs in a user with a session token. On success, this saves the session + * to disk, so you can retrieve the currently logged in user using + * current. + * + *

          Calls options.success or options.error on completion.

          + * + * @method become + * @param {String} sessionToken The sessionToken to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + + }, { + key: 'become', + value: function (sessionToken, options) { + if (!canUseCurrentUser) { + throw new Error('It is not memory-safe to become a user in a server environment'); + } + options = options || {}; + + var becomeOptions = { + sessionToken: sessionToken + }; + if (options.hasOwnProperty('useMasterKey')) { + becomeOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.become(becomeOptions)._thenRunCallbacks(options); + } + }, { + key: 'logInWith', + value: function (provider, options) { + return ParseUser._logInWith(provider, options); + } + + /** + * Logs out the currently logged in user session. This will remove the + * session from disk, log out of linked services, and future calls to + * current will return null. + * @method logOut + * @static + * @return {Parse.Promise} A promise that is resolved when the session is + * destroyed on the server. + */ + + }, { + key: 'logOut', + value: function () { + if (!canUseCurrentUser) { + throw new Error('There is no current user user on a node.js server environment.'); + } + + var controller = _CoreManager2.default.getUserController(); + return controller.logOut(); + } + + /** + * Requests a password reset email to be sent to the specified email address + * associated with the user account. This email allows the user to securely + * reset their password on the Parse site. + * + *

          Calls options.success or options.error on completion.

          + * + * @method requestPasswordReset + * @param {String} email The email address associated with the user that + * forgot their password. + * @param {Object} options A Backbone-style options object. + * @static + */ + + }, { + key: 'requestPasswordReset', + value: function (email, options) { + options = options || {}; + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + + var controller = _CoreManager2.default.getUserController(); + return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); + } + + /** + * Allow someone to define a custom User class without className + * being rewritten to _User. The default behavior is to rewrite + * User to _User for legacy reasons. This allows developers to + * override that behavior. + * + * @method allowCustomUserClass + * @param {Boolean} isAllowed Whether or not to allow custom User class + * @static + */ + + }, { + key: 'allowCustomUserClass', + value: function (isAllowed) { + _CoreManager2.default.set('PERFORM_USER_REWRITE', !isAllowed); + } + + /** + * Allows a legacy application to start using revocable sessions. If the + * current session token is not revocable, a request will be made for a new, + * revocable session. + * It is not necessary to call this method from cloud code unless you are + * handling user signup or login from the server side. In a cloud code call, + * this function will not attempt to upgrade the current token. + * @method enableRevocableSession + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is resolved when the process has + * completed. If a replacement session token is requested, the promise + * will be resolved after a new token has been fetched. + */ + + }, { + key: 'enableRevocableSession', + value: function (options) { + options = options || {}; + _CoreManager2.default.set('FORCE_REVOCABLE_SESSION', true); + if (canUseCurrentUser) { + var current = ParseUser.current(); + if (current) { + return current._upgradeToRevocableSession(options); + } + } + return _ParsePromise2.default.as()._thenRunCallbacks(options); + } + + /** + * Enables the use of become or the current user in a server + * environment. These features are disabled by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method enableUnsafeCurrentUser + * @static + */ + + }, { + key: 'enableUnsafeCurrentUser', + value: function () { + canUseCurrentUser = true; + } + + /** + * Disables the use of become or the current user in any environment. + * These features are disabled on servers by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method disableUnsafeCurrentUser + * @static + */ + + }, { + key: 'disableUnsafeCurrentUser', + value: function () { + canUseCurrentUser = false; + } + }, { + key: '_registerAuthenticationProvider', + value: function (provider) { + authProviders[provider.getAuthType()] = provider; + // Synchronize the current user with the auth provider. + ParseUser.currentAsync().then(function (current) { + if (current) { + current._synchronizeAuthData(provider.getAuthType()); + } + }); + } + }, { + key: '_logInWith', + value: function (provider, options) { + var user = new ParseUser(); + return user._linkWith(provider, options); + } + }, { + key: '_clearCache', + value: function () { + currentUserCache = null; + currentUserCacheMatchesDisk = false; + } + }, { + key: '_setCurrentUserCache', + value: function (user) { + currentUserCache = user; + } + }]); + return ParseUser; +}(_ParseObject3.default); + +exports.default = ParseUser; + +_ParseObject3.default.registerSubclass('_User', ParseUser); + +var DefaultController = { + updateUserOnDisk: function (user) { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var json = user.toJSON(); + json.className = '_User'; + return _Storage2.default.setItemAsync(path, (0, _stringify2.default)(json)).then(function () { + return user; + }); + }, + removeUserFromDisk: function () { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + currentUserCacheMatchesDisk = true; + currentUserCache = null; + return _Storage2.default.removeItemAsync(path); + }, + setCurrentUser: function (user) { + currentUserCache = user; + user._cleanupAuthData(); + user._synchronizeAllAuthData(); + return DefaultController.updateUserOnDisk(user); + }, + currentUser: function () { + if (currentUserCache) { + return currentUserCache; + } + if (currentUserCacheMatchesDisk) { + return null; + } + if (_Storage2.default.async()) { + throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); + } + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var userData = _Storage2.default.getItem(path); + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return null; + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = _ParseObject3.default.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return current; + }, + currentUserAsync: function () { + if (currentUserCache) { + return _ParsePromise2.default.as(currentUserCache); + } + if (currentUserCacheMatchesDisk) { + return _ParsePromise2.default.as(null); + } + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + return _Storage2.default.getItemAsync(path).then(function (userData) { + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return _ParsePromise2.default.as(null); + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = _ParseObject3.default.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return _ParsePromise2.default.as(current); + }); + }, + signUp: function (user, attrs, options) { + var username = attrs && attrs.username || user.get('username'); + var password = attrs && attrs.password || user.get('password'); + + if (!username || !username.length) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); + } + if (!password || !password.length) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); + } + + return user.save(attrs, options).then(function () { + // Clear the password field + user._finishFetch({ password: undefined }); + + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + }, + logIn: function (user, options) { + var RESTController = _CoreManager2.default.getRESTController(); + var stateController = _CoreManager2.default.getObjectStateController(); + var auth = { + username: user.get('username'), + password: user.get('password') + }; + return RESTController.request('GET', 'login', auth, options).then(function (response, status) { + user._migrateId(response.objectId); + user._setExisted(true); + stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); + stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); + response.password = undefined; + user._finishFetch(response); + if (!canUseCurrentUser) { + // We can't set the current user, so just return the one we logged in + return _ParsePromise2.default.as(user); + } + return DefaultController.setCurrentUser(user); + }); + }, + become: function (options) { + var user = new ParseUser(); + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('GET', 'users/me', {}, options).then(function (response, status) { + user._finishFetch(response); + user._setExisted(true); + return DefaultController.setCurrentUser(user); + }); + }, + logOut: function () { + return DefaultController.currentUserAsync().then(function (currentUser) { + var path = _Storage2.default.generatePath(CURRENT_USER_KEY); + var promise = _Storage2.default.removeItemAsync(path); + var RESTController = _CoreManager2.default.getRESTController(); + if (currentUser !== null) { + var currentSession = currentUser.getSessionToken(); + if (currentSession && (0, _isRevocableSession2.default)(currentSession)) { + promise = promise.then(function () { + return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); + }); + } + currentUser._logOutWithAll(); + currentUser._finishFetch({ sessionToken: undefined }); + } + currentUserCacheMatchesDisk = true; + currentUserCache = null; + + return promise; + }); + }, + requestPasswordReset: function (email, options) { + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); + }, + upgradeToRevocableSession: function (user, options) { + var token = user.getSessionToken(); + if (!token) { + return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.SESSION_MISSING, 'Cannot upgrade a user with no session token')); + } + + options.sessionToken = token; + + var RESTController = _CoreManager2.default.getRESTController(); + return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(function (result) { + var session = new _ParseSession2.default(); + session._finishFetch(result); + user._finishFetch({ sessionToken: session.getSessionToken() }); + if (user.isCurrent()) { + return DefaultController.setCurrentUser(user); + } + return _ParsePromise2.default.as(user); + }); + }, + linkWith: function (user, authData) { + return user.save({ authData: authData }).then(function () { + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + } +}; + +_CoreManager2.default.setUserController(DefaultController); \ No newline at end of file diff --git a/lib/node/Push.js b/lib/node/Push.js new file mode 100644 index 000000000..cfb740767 --- /dev/null +++ b/lib/node/Push.js @@ -0,0 +1,98 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.send = send; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParseQuery = require('./ParseQuery'); + +var _ParseQuery2 = _interopRequireDefault(_ParseQuery); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Contains functions to deal with Push in Parse. + * @class Parse.Push + * @static + */ + +/** + * Sends a push notification. + * @method send + * @param {Object} data - The data of the push notification. Valid fields + * are: + *
            + *
          1. channels - An Array of channels to push to.
          2. + *
          3. push_time - A Date object for when to send the push.
          4. + *
          5. expiration_time - A Date object for when to expire + * the push.
          6. + *
          7. expiration_interval - The seconds from now to expire the push.
          8. + *
          9. where - A Parse.Query over Parse.Installation that is used to match + * a set of installations to push to.
          10. + *
          11. data - The data to send as part of the push
          12. + *
              + * @param {Object} options An object that has an optional success function, + * that takes no arguments and will be called on a successful push, and + * an error function that takes a Parse.Error and will be called if the push + * failed. + * @return {Parse.Promise} A promise that is fulfilled when the push request + * completes. + */ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function send(data, options) { + options = options || {}; + + if (data.where && data.where instanceof _ParseQuery2.default) { + data.where = data.where.toJSON().where; + } + + if (data.push_time && (0, _typeof3.default)(data.push_time) === 'object') { + data.push_time = data.push_time.toJSON(); + } + + if (data.expiration_time && (0, _typeof3.default)(data.expiration_time) === 'object') { + data.expiration_time = data.expiration_time.toJSON(); + } + + if (data.expiration_time && data.expiration_interval) { + throw new Error('expiration_time and expiration_interval cannot both be set.'); + } + + return _CoreManager2.default.getPushController().send(data, { + useMasterKey: options.useMasterKey + })._thenRunCallbacks(options); +} + +var DefaultController = { + send: function (data, options) { + var RESTController = _CoreManager2.default.getRESTController(); + + var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); + + return request._thenRunCallbacks(options); + } +}; + +_CoreManager2.default.setPushController(DefaultController); \ No newline at end of file diff --git a/lib/node/RESTController.js b/lib/node/RESTController.js new file mode 100644 index 000000000..b8e0541c5 --- /dev/null +++ b/lib/node/RESTController.js @@ -0,0 +1,250 @@ +'use strict'; + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _stringify = require('babel-runtime/core-js/json/stringify'); + +var _stringify2 = _interopRequireDefault(_stringify); + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParseError = require('./ParseError'); + +var _ParseError2 = _interopRequireDefault(_ParseError); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _Storage = require('./Storage'); + +var _Storage2 = _interopRequireDefault(_Storage); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var XHR = null; +if (typeof XMLHttpRequest !== 'undefined') { + XHR = XMLHttpRequest; +} + +XHR = require('xmlhttprequest').XMLHttpRequest; + + +var useXDomainRequest = false; +if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { + useXDomainRequest = true; +} + +function ajaxIE9(method, url, data) { + var promise = new _ParsePromise2.default(); + var xdr = new XDomainRequest(); + xdr.onload = function () { + var response; + try { + response = JSON.parse(xdr.responseText); + } catch (e) { + promise.reject(e); + } + if (response) { + promise.resolve(response); + } + }; + xdr.onerror = xdr.ontimeout = function () { + // Let's fake a real error message. + var fakeResponse = { + responseText: (0, _stringify2.default)({ + code: _ParseError2.default.X_DOMAIN_REQUEST, + error: 'IE\'s XDomainRequest does not supply error info.' + }) + }; + promise.reject(fakeResponse); + }; + xdr.onprogress = function () {}; + xdr.open(method, url); + xdr.send(data); + return promise; +} + +var RESTController = { + ajax: function (method, url, data, headers) { + if (useXDomainRequest) { + return ajaxIE9(method, url, data, headers); + } + + var promise = new _ParsePromise2.default(); + var attempts = 0; + + (function dispatch() { + if (XHR == null) { + throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); + } + var handled = false; + var xhr = new XHR(); + + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4 || handled) { + return; + } + handled = true; + + if (xhr.status >= 200 && xhr.status < 300) { + var response; + try { + response = JSON.parse(xhr.responseText); + } catch (e) { + promise.reject(e.toString()); + } + if (response) { + promise.resolve(response, xhr.status, xhr); + } + } else if (xhr.status >= 500 || xhr.status === 0) { + // retry on 5XX or node-xmlhttprequest error + if (++attempts < _CoreManager2.default.get('REQUEST_ATTEMPT_LIMIT')) { + // Exponentially-growing random delay + var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); + setTimeout(dispatch, delay); + } else if (xhr.status === 0) { + promise.reject('Unable to connect to the Parse API'); + } else { + // After the retry limit is reached, fail + promise.reject(xhr); + } + } else { + promise.reject(xhr); + } + }; + + headers = headers || {}; + if (typeof headers['Content-Type'] !== 'string') { + headers['Content-Type'] = 'text/plain'; // Avoid pre-flight + } + if (_CoreManager2.default.get('IS_NODE')) { + headers['User-Agent'] = 'Parse/' + _CoreManager2.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; + } + + xhr.open(method, url, true); + for (var h in headers) { + xhr.setRequestHeader(h, headers[h]); + } + xhr.send(data); + })(); + + return promise; + }, + request: function (method, path, data, options) { + options = options || {}; + var url = _CoreManager2.default.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += path; + + var payload = {}; + if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') { + for (var k in data) { + payload[k] = data[k]; + } + } + + if (method !== 'POST') { + payload._method = method; + method = 'POST'; + } + + payload._ApplicationId = _CoreManager2.default.get('APPLICATION_ID'); + var jsKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); + if (jsKey) { + payload._JavaScriptKey = jsKey; + } + payload._ClientVersion = _CoreManager2.default.get('VERSION'); + + var useMasterKey = options.useMasterKey; + if (typeof useMasterKey === 'undefined') { + useMasterKey = _CoreManager2.default.get('USE_MASTER_KEY'); + } + if (useMasterKey) { + if (_CoreManager2.default.get('MASTER_KEY')) { + delete payload._JavaScriptKey; + payload._MasterKey = _CoreManager2.default.get('MASTER_KEY'); + } else { + throw new Error('Cannot use the Master Key, it has not been provided.'); + } + } + + if (_CoreManager2.default.get('FORCE_REVOCABLE_SESSION')) { + payload._RevocableSession = '1'; + } + + var installationId = options.installationId; + var installationIdPromise; + if (installationId && typeof installationId === 'string') { + installationIdPromise = _ParsePromise2.default.as(installationId); + } else { + var installationController = _CoreManager2.default.getInstallationController(); + installationIdPromise = installationController.currentInstallationId(); + } + + return installationIdPromise.then(function (iid) { + payload._InstallationId = iid; + var userController = _CoreManager2.default.getUserController(); + if (options && typeof options.sessionToken === 'string') { + return _ParsePromise2.default.as(options.sessionToken); + } else if (userController) { + return userController.currentUserAsync().then(function (user) { + if (user) { + return _ParsePromise2.default.as(user.getSessionToken()); + } + return _ParsePromise2.default.as(null); + }); + } + return _ParsePromise2.default.as(null); + }).then(function (token) { + if (token) { + payload._SessionToken = token; + } + + var payloadString = (0, _stringify2.default)(payload); + + return RESTController.ajax(method, url, payloadString); + }).then(null, function (response) { + // Transform the error into an instance of ParseError by trying to parse + // the error string as JSON + var error; + if (response && response.responseText) { + try { + var errorJSON = JSON.parse(response.responseText); + error = new _ParseError2.default(errorJSON.code, errorJSON.error); + } catch (e) { + // If we fail to parse the error text, that's okay. + error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); + } + } else { + error = new _ParseError2.default(_ParseError2.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify2.default)(response)); + } + + return _ParsePromise2.default.error(error); + }); + }, + _setXHR: function (xhr) { + XHR = xhr; + } +}; + +module.exports = RESTController; \ No newline at end of file diff --git a/lib/node/SingleInstanceStateController.js b/lib/node/SingleInstanceStateController.js new file mode 100644 index 000000000..545dd4c5d --- /dev/null +++ b/lib/node/SingleInstanceStateController.js @@ -0,0 +1,160 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.getState = getState; +exports.initializeState = initializeState; +exports.removeState = removeState; +exports.getServerData = getServerData; +exports.setServerData = setServerData; +exports.getPendingOps = getPendingOps; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.getObjectCache = getObjectCache; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; +exports.enqueueTask = enqueueTask; +exports.clearAllState = clearAllState; +exports.duplicateState = duplicateState; + +var _ObjectStateMutations = require('./ObjectStateMutations'); + +var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +var objectState = {}; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function getState(obj) { + var classData = objectState[obj.className]; + if (classData) { + return classData[obj.id] || null; + } + return null; +} + +function initializeState(obj, initial) { + var state = getState(obj); + if (state) { + return state; + } + if (!objectState[obj.className]) { + objectState[obj.className] = {}; + } + if (!initial) { + initial = ObjectStateMutations.defaultState(); + } + state = objectState[obj.className][obj.id] = initial; + return state; +} + +function removeState(obj) { + var state = getState(obj); + if (state === null) { + return null; + } + delete objectState[obj.className][obj.id]; + return state; +} + +function getServerData(obj) { + var state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +function setServerData(obj, attributes) { + var serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +function getPendingOps(obj) { + var state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +function setPendingOp(obj, attr, op) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +function pushPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +function popPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +function mergeFirstPendingState(obj) { + var pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +function getObjectCache(obj) { + var state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +function estimateAttribute(obj, attr) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +function estimateAttributes(obj) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +function commitServerChanges(obj, changes) { + var state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +function enqueueTask(obj, task) { + var state = initializeState(obj); + return state.tasks.enqueue(task); +} + +function clearAllState() { + objectState = {}; +} + +function duplicateState(source, dest) { + dest.id = source.id; +} \ No newline at end of file diff --git a/lib/node/Storage.js b/lib/node/Storage.js new file mode 100644 index 000000000..e4cd978a5 --- /dev/null +++ b/lib/node/Storage.js @@ -0,0 +1,93 @@ +'use strict'; + +var _CoreManager = require('./CoreManager'); + +var _CoreManager2 = _interopRequireDefault(_CoreManager); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = { + async: function () { + var controller = _CoreManager2.default.getStorageController(); + return !!controller.async; + }, + getItem: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.getItem(path); + }, + getItemAsync: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.getItemAsync(path); + } + return _ParsePromise2.default.as(controller.getItem(path)); + }, + setItem: function (path, value) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.setItem(path, value); + }, + setItemAsync: function (path, value) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.setItemAsync(path, value); + } + return _ParsePromise2.default.as(controller.setItem(path, value)); + }, + removeItem: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.removeItem(path); + }, + removeItemAsync: function (path) { + var controller = _CoreManager2.default.getStorageController(); + if (controller.async === 1) { + return controller.removeItemAsync(path); + } + return _ParsePromise2.default.as(controller.removeItem(path)); + }, + generatePath: function (path) { + if (!_CoreManager2.default.get('APPLICATION_ID')) { + throw new Error('You need to call Parse.initialize before using Parse.'); + } + if (typeof path !== 'string') { + throw new Error('Tried to get a Storage path that was not a String.'); + } + if (path[0] === '/') { + path = path.substr(1); + } + return 'Parse/' + _CoreManager2.default.get('APPLICATION_ID') + '/' + path; + }, + _clear: function () { + var controller = _CoreManager2.default.getStorageController(); + if (controller.hasOwnProperty('clear')) { + controller.clear(); + } + } +}; + +_CoreManager2.default.setStorageController(require('./StorageController.default')); \ No newline at end of file diff --git a/lib/node/StorageController.browser.js b/lib/node/StorageController.browser.js new file mode 100644 index 000000000..d372924a0 --- /dev/null +++ b/lib/node/StorageController.browser.js @@ -0,0 +1,41 @@ +'use strict'; + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var StorageController = { + async: 0, + + getItem: function (path) { + return localStorage.getItem(path); + }, + setItem: function (path, value) { + try { + localStorage.setItem(path, value); + } catch (e) { + // Quota exceeded, possibly due to Safari Private Browsing mode + } + }, + removeItem: function (path) { + localStorage.removeItem(path); + }, + clear: function () { + localStorage.clear(); + } +}; /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/node/StorageController.default.js b/lib/node/StorageController.default.js new file mode 100644 index 000000000..460c1e2ca --- /dev/null +++ b/lib/node/StorageController.default.js @@ -0,0 +1,41 @@ +"use strict"; + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +// When there is no native storage interface, we default to an in-memory map + +var memMap = {}; +var StorageController = { + async: 0, + + getItem: function (path) { + if (memMap.hasOwnProperty(path)) { + return memMap[path]; + } + return null; + }, + setItem: function (path, value) { + memMap[path] = String(value); + }, + removeItem: function (path) { + delete memMap[path]; + }, + clear: function () { + for (var key in memMap) { + if (memMap.hasOwnProperty(key)) { + delete memMap[key]; + } + } + } +}; + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/node/StorageController.react-native.js b/lib/node/StorageController.react-native.js new file mode 100644 index 000000000..b92ae6141 --- /dev/null +++ b/lib/node/StorageController.react-native.js @@ -0,0 +1,67 @@ +'use strict'; + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +var _reactNative = require('react-native/Libraries/react-native/react-native.js'); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var StorageController = { + async: 1, + + getItemAsync: function (path) { + var p = new _ParsePromise2.default(); + _reactNative.AsyncStorage.getItem(path, function (err, value) { + if (err) { + p.reject(err); + } else { + p.resolve(value); + } + }); + return p; + }, + setItemAsync: function (path, value) { + var p = new _ParsePromise2.default(); + _reactNative.AsyncStorage.setItem(path, value, function (err) { + if (err) { + p.reject(err); + } else { + p.resolve(value); + } + }); + return p; + }, + removeItemAsync: function (path) { + var p = new _ParsePromise2.default(); + _reactNative.AsyncStorage.removeItem(path, function (err) { + if (err) { + p.reject(err); + } else { + p.resolve(); + } + }); + return p; + }, + clear: function () { + _reactNative.AsyncStorage.clear(); + } +}; +// RN packager nonsense + + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/node/TaskQueue.js b/lib/node/TaskQueue.js new file mode 100644 index 000000000..4bf6bffd0 --- /dev/null +++ b/lib/node/TaskQueue.js @@ -0,0 +1,77 @@ +'use strict'; + +var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); + +var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); + +var _createClass2 = require('babel-runtime/helpers/createClass'); + +var _createClass3 = _interopRequireDefault(_createClass2); + +var _ParsePromise = require('./ParsePromise'); + +var _ParsePromise2 = _interopRequireDefault(_ParsePromise); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +var TaskQueue = function () { + function TaskQueue() { + (0, _classCallCheck3.default)(this, TaskQueue); + + this.queue = []; + } + + (0, _createClass3.default)(TaskQueue, [{ + key: 'enqueue', + value: function (task) { + var _this = this; + + var taskComplete = new _ParsePromise2.default(); + this.queue.push({ + task: task, + _completion: taskComplete + }); + if (this.queue.length === 1) { + task().then(function () { + _this._dequeue(); + taskComplete.resolve(); + }, function (error) { + _this._dequeue(); + taskComplete.reject(error); + }); + } + return taskComplete; + } + }, { + key: '_dequeue', + value: function () { + var _this2 = this; + + this.queue.shift(); + if (this.queue.length) { + var next = this.queue[0]; + next.task().then(function () { + _this2._dequeue(); + next._completion.resolve(); + }, function (error) { + _this2._dequeue(); + next._completion.reject(error); + }); + } + } + }]); + return TaskQueue; +}(); /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +module.exports = TaskQueue; \ No newline at end of file diff --git a/lib/node/UniqueInstanceStateController.js b/lib/node/UniqueInstanceStateController.js new file mode 100644 index 000000000..12b8ab04d --- /dev/null +++ b/lib/node/UniqueInstanceStateController.js @@ -0,0 +1,189 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _weakMap = require('babel-runtime/core-js/weak-map'); + +var _weakMap2 = _interopRequireDefault(_weakMap); + +exports.getState = getState; +exports.initializeState = initializeState; +exports.removeState = removeState; +exports.getServerData = getServerData; +exports.setServerData = setServerData; +exports.getPendingOps = getPendingOps; +exports.setPendingOp = setPendingOp; +exports.pushPendingState = pushPendingState; +exports.popPendingState = popPendingState; +exports.mergeFirstPendingState = mergeFirstPendingState; +exports.getObjectCache = getObjectCache; +exports.estimateAttribute = estimateAttribute; +exports.estimateAttributes = estimateAttributes; +exports.commitServerChanges = commitServerChanges; +exports.enqueueTask = enqueueTask; +exports.duplicateState = duplicateState; +exports.clearAllState = clearAllState; + +var _ObjectStateMutations = require('./ObjectStateMutations'); + +var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); + +var _TaskQueue = require('./TaskQueue'); + +var _TaskQueue2 = _interopRequireDefault(_TaskQueue); + +function _interopRequireWildcard(obj) { + if (obj && obj.__esModule) { + return obj; + } else { + var newObj = {};if (obj != null) { + for (var key in obj) { + if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; + } + }newObj.default = obj;return newObj; + } +} + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var objectState = new _weakMap2.default(); + +function getState(obj) { + var classData = objectState.get(obj); + return classData || null; +} + +function initializeState(obj, initial) { + var state = getState(obj); + if (state) { + return state; + } + if (!initial) { + initial = { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new _TaskQueue2.default(), + existed: false + }; + } + state = initial; + objectState.set(obj, state); + return state; +} + +function removeState(obj) { + var state = getState(obj); + if (state === null) { + return null; + } + objectState.delete(obj); + return state; +} + +function getServerData(obj) { + var state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +function setServerData(obj, attributes) { + var serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +function getPendingOps(obj) { + var state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +function setPendingOp(obj, attr, op) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +function pushPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +function popPendingState(obj) { + var pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +function mergeFirstPendingState(obj) { + var pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +function getObjectCache(obj) { + var state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +function estimateAttribute(obj, attr) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +function estimateAttributes(obj) { + var serverData = getServerData(obj); + var pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +function commitServerChanges(obj, changes) { + var state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +function enqueueTask(obj, task) { + var state = initializeState(obj); + return state.tasks.enqueue(task); +} + +function duplicateState(source, dest) { + var oldState = initializeState(source); + var newState = initializeState(dest); + for (var key in oldState.serverData) { + newState.serverData[key] = oldState.serverData[key]; + } + for (var index = 0; index < oldState.pendingOps.length; index++) { + for (var _key in oldState.pendingOps[index]) { + newState.pendingOps[index][_key] = oldState.pendingOps[index][_key]; + } + } + for (var _key2 in oldState.objectCache) { + newState.objectCache[_key2] = oldState.objectCache[_key2]; + } + newState.existed = oldState.existed; +} + +function clearAllState() { + objectState = new _weakMap2.default(); +} \ No newline at end of file diff --git a/lib/node/arrayContainsObject.js b/lib/node/arrayContainsObject.js new file mode 100644 index 000000000..e9d7949c9 --- /dev/null +++ b/lib/node/arrayContainsObject.js @@ -0,0 +1,35 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = arrayContainsObject; + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function arrayContainsObject(array, object) { + if (array.indexOf(object) > -1) { + return true; + } + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof _ParseObject2.default && array[i].className === object.className && array[i]._getId() === object._getId()) { + return true; + } + } + return false; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ \ No newline at end of file diff --git a/lib/node/canBeSerialized.js b/lib/node/canBeSerialized.js new file mode 100644 index 000000000..e7b7e2282 --- /dev/null +++ b/lib/node/canBeSerialized.js @@ -0,0 +1,82 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = canBeSerialized; + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +function canBeSerialized(obj) { + if (!(obj instanceof _ParseObject2.default)) { + return true; + } + var attributes = obj.attributes; + for (var attr in attributes) { + var val = attributes[attr]; + if (!canBeSerializedHelper(val)) { + return false; + } + } + return true; +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function canBeSerializedHelper(value) { + if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { + return true; + } + if (value instanceof _ParseRelation2.default) { + return true; + } + if (value instanceof _ParseObject2.default) { + return !!value.id; + } + if (value instanceof _ParseFile2.default) { + if (value.url()) { + return true; + } + return false; + } + if (Array.isArray(value)) { + for (var i = 0; i < value.length; i++) { + if (!canBeSerializedHelper(value[i])) { + return false; + } + } + return true; + } + for (var k in value) { + if (!canBeSerializedHelper(value[k])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/node/decode.js b/lib/node/decode.js new file mode 100644 index 000000000..98a182789 --- /dev/null +++ b/lib/node/decode.js @@ -0,0 +1,93 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = decode; + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseOp = require('./ParseOp'); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function decode(value) { + if (value === null || (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { + return value; + } + if (Array.isArray(value)) { + var dup = []; + value.forEach(function (v, i) { + dup[i] = decode(v); + }); + return dup; + } + if (typeof value.__op === 'string') { + return (0, _ParseOp.opFromJSON)(value); + } + if (value.__type === 'Pointer' && value.className) { + return _ParseObject2.default.fromJSON(value); + } + if (value.__type === 'Object' && value.className) { + return _ParseObject2.default.fromJSON(value); + } + if (value.__type === 'Relation') { + // The parent and key fields will be populated by the parent + var relation = new _ParseRelation2.default(null, null); + relation.targetClassName = value.className; + return relation; + } + if (value.__type === 'Date') { + return new Date(value.iso); + } + if (value.__type === 'File') { + return _ParseFile2.default.fromJSON(value); + } + if (value.__type === 'GeoPoint') { + return new _ParseGeoPoint2.default({ + latitude: value.latitude, + longitude: value.longitude + }); + } + var copy = {}; + for (var k in value) { + copy[k] = decode(value[k]); + } + return copy; +} \ No newline at end of file diff --git a/lib/node/encode.js b/lib/node/encode.js new file mode 100644 index 000000000..8c3aee6e3 --- /dev/null +++ b/lib/node/encode.js @@ -0,0 +1,104 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +exports.default = function (value, disallowObjects, forcePointers, seen) { + return encode(value, !!disallowObjects, !!forcePointers, seen || []); +}; + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseOp = require('./ParseOp'); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var toString = Object.prototype.toString; + +function encode(value, disallowObjects, forcePointers, seen) { + if (value instanceof _ParseObject2.default) { + if (disallowObjects) { + throw new Error('Parse Objects not allowed here'); + } + var seenEntry = value.id ? value.className + ':' + value.id : value; + if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || (0, _keys2.default)(value._getServerData()).length < 1) { + return value.toPointer(); + } + seen = seen.concat(seenEntry); + return value._toFullJSON(seen); + } + if (value instanceof _ParseOp.Op || value instanceof _ParseACL2.default || value instanceof _ParseGeoPoint2.default || value instanceof _ParseRelation2.default) { + return value.toJSON(); + } + if (value instanceof _ParseFile2.default) { + if (!value.url()) { + throw new Error('Tried to encode an unsaved file.'); + } + return value.toJSON(); + } + if (toString.call(value) === '[object Date]') { + if (isNaN(value)) { + throw new Error('Tried to encode an invalid date.'); + } + return { __type: 'Date', iso: value.toJSON() }; + } + if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { + return value.source; + } + + if (Array.isArray(value)) { + return value.map(function (v) { + return encode(v, disallowObjects, forcePointers, seen); + }); + } + + if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { + var output = {}; + for (var k in value) { + output[k] = encode(value[k], disallowObjects, forcePointers, seen); + } + return output; + } + + return value; +} \ No newline at end of file diff --git a/lib/node/equals.js b/lib/node/equals.js new file mode 100644 index 000000000..32edcc8a7 --- /dev/null +++ b/lib/node/equals.js @@ -0,0 +1,84 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _keys = require('babel-runtime/core-js/object/keys'); + +var _keys2 = _interopRequireDefault(_keys); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = equals; + +var _ParseACL = require('./ParseACL'); + +var _ParseACL2 = _interopRequireDefault(_ParseACL); + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseGeoPoint = require('./ParseGeoPoint'); + +var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +function equals(a, b) { + if ((typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== (typeof b === 'undefined' ? 'undefined' : (0, _typeof3.default)(b))) { + return false; + } + + if (!a || (typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== 'object') { + // a is a primitive + return a === b; + } + + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b)) { + return false; + } + if (a.length !== b.length) { + return false; + } + for (var i = a.length; i--;) { + if (!equals(a[i], b[i])) { + return false; + } + } + return true; + } + + if (a instanceof _ParseACL2.default || a instanceof _ParseFile2.default || a instanceof _ParseGeoPoint2.default || a instanceof _ParseObject2.default) { + return a.equals(b); + } + + if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) { + return false; + } + for (var k in a) { + if (!equals(a[k], b[k])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/node/escape.js b/lib/node/escape.js new file mode 100644 index 000000000..4693baaed --- /dev/null +++ b/lib/node/escape.js @@ -0,0 +1,31 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = escape; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var encoded = { + '&': '&', + '<': '<', + '>': '>', + '/': '/', + '\'': ''', + '"': '"' +}; + +function escape(str) { + return str.replace(/[&<>\/'"]/g, function (char) { + return encoded[char]; + }); +} \ No newline at end of file diff --git a/lib/node/isRevocableSession.js b/lib/node/isRevocableSession.js new file mode 100644 index 000000000..92b8230e9 --- /dev/null +++ b/lib/node/isRevocableSession.js @@ -0,0 +1,20 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = isRevocableSession; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function isRevocableSession(token) { + return token.indexOf('r:') > -1; +} \ No newline at end of file diff --git a/lib/node/parseDate.js b/lib/node/parseDate.js new file mode 100644 index 000000000..48e061b05 --- /dev/null +++ b/lib/node/parseDate.js @@ -0,0 +1,34 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = parseDate; +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function parseDate(iso8601) { + var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); + var match = regexp.exec(iso8601); + if (!match) { + return null; + } + + var year = match[1] || 0; + var month = (match[2] || 1) - 1; + var day = match[3] || 0; + var hour = match[4] || 0; + var minute = match[5] || 0; + var second = match[6] || 0; + var milli = match[8] || 0; + + return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); +} \ No newline at end of file diff --git a/lib/node/unique.js b/lib/node/unique.js new file mode 100644 index 000000000..157b3560a --- /dev/null +++ b/lib/node/unique.js @@ -0,0 +1,45 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.default = unique; + +var _arrayContainsObject = require('./arrayContainsObject'); + +var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function unique(arr) { + var uniques = []; + arr.forEach(function (value) { + if (value instanceof _ParseObject2.default) { + if (!(0, _arrayContainsObject2.default)(uniques, value)) { + uniques.push(value); + } + } else { + if (uniques.indexOf(value) < 0) { + uniques.push(value); + } + } + }); + return uniques; +} \ No newline at end of file diff --git a/lib/node/unsavedChildren.js b/lib/node/unsavedChildren.js new file mode 100644 index 000000000..073efd70b --- /dev/null +++ b/lib/node/unsavedChildren.js @@ -0,0 +1,102 @@ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof2 = require('babel-runtime/helpers/typeof'); + +var _typeof3 = _interopRequireDefault(_typeof2); + +exports.default = unsavedChildren; + +var _ParseFile = require('./ParseFile'); + +var _ParseFile2 = _interopRequireDefault(_ParseFile); + +var _ParseObject = require('./ParseObject'); + +var _ParseObject2 = _interopRequireDefault(_ParseObject); + +var _ParseRelation = require('./ParseRelation'); + +var _ParseRelation2 = _interopRequireDefault(_ParseRelation); + +function _interopRequireDefault(obj) { + return obj && obj.__esModule ? obj : { default: obj }; +} + +/** + * Return an array of unsaved children, which are either Parse Objects or Files. + * If it encounters any dirty Objects without Ids, it will throw an exception. + */ +function unsavedChildren(obj, allowDeepUnsaved) { + var encountered = { + objects: {}, + files: [] + }; + var identifier = obj.className + ':' + obj._getId(); + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if ((0, _typeof3.default)(attributes[attr]) === 'object') { + traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); + } + } + var unsaved = []; + for (var id in encountered.objects) { + if (id !== identifier && encountered.objects[id] !== true) { + unsaved.push(encountered.objects[id]); + } + } + return unsaved.concat(encountered.files); +} /** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { + if (obj instanceof _ParseObject2.default) { + if (!obj.id && shouldThrow) { + throw new Error('Cannot create a pointer to an unsaved Object.'); + } + var identifier = obj.className + ':' + obj._getId(); + if (!encountered.objects[identifier]) { + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if ((0, _typeof3.default)(attributes[attr]) === 'object') { + traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); + } + } + } + return; + } + if (obj instanceof _ParseFile2.default) { + if (!obj.url() && encountered.files.indexOf(obj) < 0) { + encountered.files.push(obj); + } + return; + } + if (obj instanceof _ParseRelation2.default) { + return; + } + if (Array.isArray(obj)) { + obj.forEach(function (el) { + if ((typeof el === 'undefined' ? 'undefined' : (0, _typeof3.default)(el)) === 'object') { + traverse(el, encountered, shouldThrow, allowDeepUnsaved); + } + }); + } + for (var k in obj) { + if ((0, _typeof3.default)(obj[k]) === 'object') { + traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); + } + } +} \ No newline at end of file diff --git a/lib/react-native/Analytics.js b/lib/react-native/Analytics.js new file mode 100644 index 000000000..92561a2bb --- /dev/null +++ b/lib/react-native/Analytics.js @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; + +/** + * Parse.Analytics provides an interface to Parse's logging and analytics + * backend. + * + * @class Parse.Analytics + * @static + */ + +/** + * Tracks the occurrence of a custom event with additional dimensions. + * Parse will store a data point at the time of invocation with the given + * event name. + * + * Dimensions will allow segmentation of the occurrences of this custom + * event. Keys and values should be {@code String}s, and will throw + * otherwise. + * + * To track a user signup along with additional metadata, consider the + * following: + *
              + * var dimensions = {
              + *  gender: 'm',
              + *  source: 'web',
              + *  dayType: 'weekend'
              + * };
              + * Parse.Analytics.track('signup', dimensions);
              + * 
              + * + * There is a default limit of 8 dimensions per event tracked. + * + * @method track + * @param {String} name The name of the custom event to report to Parse as + * having happened. + * @param {Object} dimensions The dictionary of information by which to + * segment this event. + * @param {Object} options A Backbone-style callback object. + * @return {Parse.Promise} A promise that is resolved when the round-trip + * to the server completes. + */ +export function track(name, dimensions, options) { + name = name || ''; + name = name.replace(/^\s*/, ''); + name = name.replace(/\s*$/, ''); + if (name.length === 0) { + throw new TypeError('A name for the custom event must be provided'); + } + + for (var key in dimensions) { + if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { + throw new TypeError('track() dimensions expects keys and values of type "string".'); + } + } + + options = options || {}; + return CoreManager.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); +} + +var DefaultController = { + track(name, dimensions) { + var RESTController = CoreManager.getRESTController(); + return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); + } +}; + +CoreManager.setAnalyticsController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/Cloud.js b/lib/react-native/Cloud.js new file mode 100644 index 000000000..604707acd --- /dev/null +++ b/lib/react-native/Cloud.js @@ -0,0 +1,86 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import decode from './decode'; +import encode from './encode'; +import ParseError from './ParseError'; +import ParsePromise from './ParsePromise'; + +/** + * Contains functions for calling and declaring + * cloud functions. + *

              + * Some functions are only available from Cloud Code. + *

              + * + * @class Parse.Cloud + * @static + */ + +/** + * Makes a call to a cloud function. + * @method run + * @param {String} name The function name. + * @param {Object} data The parameters to send to the cloud function. + * @param {Object} options A Backbone-style options object + * options.success, if set, should be a function to handle a successful + * call to a cloud function. options.error should be a function that + * handles an error running the cloud function. Both functions are + * optional. Both functions take a single argument. + * @return {Parse.Promise} A promise that will be resolved with the result + * of the function. + */ +export function run(name, data, options) { + options = options || {}; + + if (typeof name !== 'string' || name.length === 0) { + throw new TypeError('Cloud function name must be a string.'); + } + + var requestOptions = {}; + if (options.useMasterKey) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.sessionToken) { + requestOptions.sessionToken = options.sessionToken; + } + + return CoreManager.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); +} + +var DefaultController = { + run(name, data, options) { + var RESTController = CoreManager.getRESTController(); + + var payload = encode(data, true); + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + requestOptions.sessionToken = options.sessionToken; + } + + var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); + + return request.then(function (res) { + var decoded = decode(res); + if (decoded && decoded.hasOwnProperty('result')) { + return ParsePromise.as(decoded.result); + } + return ParsePromise.error(new ParseError(ParseError.INVALID_JSON, 'The server returned an invalid response.')); + })._thenRunCallbacks(options); + } +}; + +CoreManager.setCloudController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/CoreManager.js b/lib/react-native/CoreManager.js new file mode 100644 index 000000000..97062e559 --- /dev/null +++ b/lib/react-native/CoreManager.js @@ -0,0 +1,188 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var config = { + // Defaults + IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, + REQUEST_ATTEMPT_LIMIT: 5, + SERVER_URL: 'https://api.parse.com/1', + LIVEQUERY_SERVER_URL: null, + VERSION: 'js' + '1.9.2', + APPLICATION_ID: null, + JAVASCRIPT_KEY: null, + MASTER_KEY: null, + USE_MASTER_KEY: false, + PERFORM_USER_REWRITE: true, + FORCE_REVOCABLE_SESSION: false +}; + +function requireMethods(name, methods, controller) { + methods.forEach(func => { + if (typeof controller[func] !== 'function') { + throw new Error(`${name} must implement ${func}()`); + } + }); +} + +module.exports = { + get: function (key) { + if (config.hasOwnProperty(key)) { + return config[key]; + } + throw new Error('Configuration key not found: ' + key); + }, + + set: function (key, value) { + config[key] = value; + }, + + /* Specialized Controller Setters/Getters */ + + setAnalyticsController(controller) { + requireMethods('AnalyticsController', ['track'], controller); + config['AnalyticsController'] = controller; + }, + + getAnalyticsController() { + return config['AnalyticsController']; + }, + + setCloudController(controller) { + requireMethods('CloudController', ['run'], controller); + config['CloudController'] = controller; + }, + + getCloudController() { + return config['CloudController']; + }, + + setConfigController(controller) { + requireMethods('ConfigController', ['current', 'get'], controller); + config['ConfigController'] = controller; + }, + + getConfigController() { + return config['ConfigController']; + }, + + setFileController(controller) { + requireMethods('FileController', ['saveFile', 'saveBase64'], controller); + config['FileController'] = controller; + }, + + getFileController() { + return config['FileController']; + }, + + setInstallationController(controller) { + requireMethods('InstallationController', ['currentInstallationId'], controller); + config['InstallationController'] = controller; + }, + + getInstallationController() { + return config['InstallationController']; + }, + + setObjectController(controller) { + requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); + config['ObjectController'] = controller; + }, + + getObjectController() { + return config['ObjectController']; + }, + + setObjectStateController(controller) { + requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); + + config['ObjectStateController'] = controller; + }, + + getObjectStateController() { + return config['ObjectStateController']; + }, + + setPushController(controller) { + requireMethods('PushController', ['send'], controller); + config['PushController'] = controller; + }, + + getPushController() { + return config['PushController']; + }, + + setQueryController(controller) { + requireMethods('QueryController', ['find'], controller); + config['QueryController'] = controller; + }, + + getQueryController() { + return config['QueryController']; + }, + + setRESTController(controller) { + requireMethods('RESTController', ['request', 'ajax'], controller); + config['RESTController'] = controller; + }, + + getRESTController() { + return config['RESTController']; + }, + + setSessionController(controller) { + requireMethods('SessionController', ['getSession'], controller); + config['SessionController'] = controller; + }, + + getSessionController() { + return config['SessionController']; + }, + + setStorageController(controller) { + if (controller.async) { + requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); + } else { + requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); + } + config['StorageController'] = controller; + }, + + getStorageController() { + return config['StorageController']; + }, + + setUserController(controller) { + requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); + config['UserController'] = controller; + }, + + getUserController() { + return config['UserController']; + }, + + setLiveQueryController(controller) { + requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); + config['LiveQueryController'] = controller; + }, + + getLiveQueryController() { + return config['LiveQueryController']; + }, + + setHooksController(controller) { + requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); + config['HooksController'] = controller; + }, + + getHooksController() { + return config['HooksController']; + } +}; \ No newline at end of file diff --git a/lib/react-native/EventEmitter.js b/lib/react-native/EventEmitter.js new file mode 100644 index 000000000..3450b4ac6 --- /dev/null +++ b/lib/react-native/EventEmitter.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * This is a simple wrapper to unify EventEmitter implementations across platforms. + */ + +{ + const EventEmitter = require('EventEmitter'); + EventEmitter.prototype.on = EventEmitter.prototype.addListener; + module.exports = EventEmitter; +} \ No newline at end of file diff --git a/lib/react-native/FacebookUtils.js b/lib/react-native/FacebookUtils.js new file mode 100644 index 000000000..24ce10c01 --- /dev/null +++ b/lib/react-native/FacebookUtils.js @@ -0,0 +1,229 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * -weak + */ + +import parseDate from './parseDate'; +import ParseUser from './ParseUser'; + +var PUBLIC_KEY = "*"; + +var initialized = false; +var requestedPermissions; +var initOptions; +var provider = { + authenticate(options) { + if (typeof FB === 'undefined') { + options.error(this, 'Facebook SDK not found.'); + } + FB.login(response => { + if (response.authResponse) { + if (options.success) { + options.success(this, { + id: response.authResponse.userID, + access_token: response.authResponse.accessToken, + expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() + }); + } + } else { + if (options.error) { + options.error(this, response); + } + } + }, { + scope: requestedPermissions + }); + }, + + restoreAuthentication(authData) { + if (authData) { + var expiration = parseDate(authData.expiration_date); + var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; + + var authResponse = { + userID: authData.id, + accessToken: authData.access_token, + expiresIn: expiresIn + }; + var newOptions = {}; + if (initOptions) { + for (var key in initOptions) { + newOptions[key] = initOptions[key]; + } + } + newOptions.authResponse = authResponse; + + // Suppress checks for login status from the browser. + newOptions.status = false; + + // If the user doesn't match the one known by the FB SDK, log out. + // Most of the time, the users will match -- it's only in cases where + // the FB SDK knows of a different user than the one being restored + // from a Parse User that logged in with username/password. + var existingResponse = FB.getAuthResponse(); + if (existingResponse && existingResponse.userID !== authResponse.userID) { + FB.logout(); + } + + FB.init(newOptions); + } + return true; + }, + + getAuthType() { + return 'facebook'; + }, + + deauthenticate() { + this.restoreAuthentication(null); + } +}; + +/** + * Provides a set of utilities for using Parse with Facebook. + * @class Parse.FacebookUtils + * @static + */ +var FacebookUtils = { + /** + * Initializes Parse Facebook integration. Call this function after you + * have loaded the Facebook Javascript SDK with the same parameters + * as you would pass to + * + * FB.init(). Parse.FacebookUtils will invoke FB.init() for you + * with these arguments. + * + * @method init + * @param {Object} options Facebook options argument as described here: + * + * FB.init(). The status flag will be coerced to 'false' because it + * interferes with Parse Facebook integration. Call FB.getLoginStatus() + * explicitly if this behavior is required by your application. + */ + init(options) { + if (typeof FB === 'undefined') { + throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); + } + initOptions = {}; + if (options) { + for (var key in options) { + initOptions[key] = options[key]; + } + } + if (initOptions.status && typeof console !== 'undefined') { + var warn = console.warn || console.log || function () {}; + warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); + } + initOptions.status = false; + FB.init(initOptions); + ParseUser._registerAuthenticationProvider(provider); + initialized = true; + }, + + /** + * Gets whether the user has their account linked to Facebook. + * + * @method isLinked + * @param {Parse.User} user User to check for a facebook link. + * The user must be logged in on this device. + * @return {Boolean} true if the user has their account + * linked to Facebook. + */ + isLinked(user) { + return user._isLinked('facebook'); + }, + + /** + * Logs in a user using Facebook. This method delegates to the Facebook + * SDK to authenticate the user, and then automatically logs in (or + * creates, in the case where it is a new user) a Parse.User. + * + * @method logIn + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + logIn(permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling logIn.'); + } + requestedPermissions = permissions; + return ParseUser._logInWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return ParseUser._logInWith('facebook', newOptions); + } + }, + + /** + * Links Facebook to an existing PFUser. This method delegates to the + * Facebook SDK to authenticate the user, and then automatically links + * the account to the Parse.User. + * + * @method link + * @param {Parse.User} user User to link to Facebook. This must be the + * current user. + * @param {String, Object} permissions The permissions required for Facebook + * log in. This is a comma-separated string of permissions. + * Alternatively, supply a Facebook authData object as described in our + * REST API docs if you want to handle getting facebook auth tokens + * yourself. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + link(user, permissions, options) { + if (!permissions || typeof permissions === 'string') { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling link.'); + } + requestedPermissions = permissions; + return user._linkWith('facebook', options); + } else { + var newOptions = {}; + if (options) { + for (var key in options) { + newOptions[key] = options[key]; + } + } + newOptions.authData = permissions; + return user._linkWith('facebook', newOptions); + } + }, + + /** + * Unlinks the Parse.User from a Facebook account. + * + * @method unlink + * @param {Parse.User} user User to unlink from Facebook. This must be the + * current user. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + unlink: function (user, options) { + if (!initialized) { + throw new Error('You must initialize FacebookUtils before calling unlink.'); + } + return user._unlinkFrom('facebook', options); + } +}; + +export default FacebookUtils; \ No newline at end of file diff --git a/lib/react-native/InstallationController.js b/lib/react-native/InstallationController.js new file mode 100644 index 000000000..75aad6d0b --- /dev/null +++ b/lib/react-native/InstallationController.js @@ -0,0 +1,54 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import ParsePromise from './ParsePromise'; +import Storage from './Storage'; + +var iidCache = null; + +function hexOctet() { + return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); +} + +function generateId() { + return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); +} + +var InstallationController = { + currentInstallationId() { + if (typeof iidCache === 'string') { + return ParsePromise.as(iidCache); + } + var path = Storage.generatePath('installationId'); + return Storage.getItemAsync(path).then(iid => { + if (!iid) { + iid = generateId(); + return Storage.setItemAsync(path, iid).then(() => { + iidCache = iid; + return iid; + }); + } + iidCache = iid; + return iid; + }); + }, + + _clearCache() { + iidCache = null; + }, + + _setInstallationIdCache(iid) { + iidCache = iid; + } +}; + +module.exports = InstallationController; \ No newline at end of file diff --git a/lib/react-native/LiveQueryClient.js b/lib/react-native/LiveQueryClient.js new file mode 100644 index 000000000..0af495cb4 --- /dev/null +++ b/lib/react-native/LiveQueryClient.js @@ -0,0 +1,430 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +import EventEmitter from './EventEmitter'; +import ParsePromise from './ParsePromise'; +import ParseObject from './ParseObject'; +import LiveQuerySubscription from './LiveQuerySubscription'; + +// The LiveQuery client inner state +const CLIENT_STATE = { + INITIALIZED: 'initialized', + CONNECTING: 'connecting', + CONNECTED: 'connected', + CLOSED: 'closed', + RECONNECTING: 'reconnecting', + DISCONNECTED: 'disconnected' +}; + +// The event type the LiveQuery client should sent to server +const OP_TYPES = { + CONNECT: 'connect', + SUBSCRIBE: 'subscribe', + UNSUBSCRIBE: 'unsubscribe', + ERROR: 'error' +}; + +// The event we get back from LiveQuery server +const OP_EVENTS = { + CONNECTED: 'connected', + SUBSCRIBED: 'subscribed', + UNSUBSCRIBED: 'unsubscribed', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +// The event the LiveQuery client should emit +const CLIENT_EMMITER_TYPES = { + CLOSE: 'close', + ERROR: 'error', + OPEN: 'open' +}; + +// The event the LiveQuery subscription should emit +const SUBSCRIPTION_EMMITER_TYPES = { + OPEN: 'open', + CLOSE: 'close', + ERROR: 'error', + CREATE: 'create', + UPDATE: 'update', + ENTER: 'enter', + LEAVE: 'leave', + DELETE: 'delete' +}; + +let generateInterval = k => { + return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; +}; + +/** + * Creates a new LiveQueryClient. + * Extends events.EventEmitter + * cloud functions. + * + * A wrapper of a standard WebSocket client. We add several useful methods to + * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. + * + * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries + * to connect to the LiveQuery server + * + * @class Parse.LiveQueryClient + * @constructor + * @param {Object} options + * @param {string} options.applicationId - applicationId of your Parse app + * @param {string} options.serverURL - the URL of your LiveQuery server + * @param {string} options.javascriptKey (optional) + * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) + * @param {string} options.sessionToken (optional) + * + * + * We expose three events to help you monitor the status of the LiveQueryClient. + * + *
              + * let Parse = require('parse/node');
              + * let LiveQueryClient = Parse.LiveQueryClient;
              + * let client = new LiveQueryClient({
              + *   applicationId: '',
              + *   serverURL: '',
              + *   javascriptKey: '',
              + *   masterKey: ''
              + *  });
              + * 
              + * + * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + *
              + * client.on('open', () => {
              + * 
              + * });
              + * + * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + *
              + * client.on('close', () => {
              + * 
              + * });
              + * + * Error - When some network error or LiveQuery server error happens, you'll get this event. + *
              + * client.on('error', (error) => {
              + * 
              + * });
              + * + * + */ +export default class LiveQueryClient extends EventEmitter { + + constructor({ + applicationId, + serverURL, + javascriptKey, + masterKey, + sessionToken + }) { + super(); + + if (!serverURL || serverURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + this.reconnectHandle = null; + this.attempts = 1;; + this.id = 0; + this.requestId = 1; + this.serverURL = serverURL; + this.applicationId = applicationId; + this.javascriptKey = javascriptKey; + this.masterKey = masterKey; + this.sessionToken = sessionToken; + this.connectPromise = new ParsePromise(); + this.subscriptions = new Map(); + this.state = CLIENT_STATE.INITIALIZED; + } + + shouldOpen() { + return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; + } + + /** + * Subscribes to a ParseQuery + * + * If you provide the sessionToken, when the LiveQuery server gets ParseObject's + * updates from parse server, it'll try to check whether the sessionToken fulfills + * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose + * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol + * here for more details. The subscription you get is the same subscription you get + * from our Standard API. + * + * @method subscribe + * @param {Object} query - the ParseQuery you want to subscribe to + * @param {string} sessionToken (optional) + * @return {Object} subscription + */ + subscribe(query, sessionToken) { + if (!query) { + return; + } + let where = query.toJSON().where; + let className = query.className; + let subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId: this.requestId, + query: { + className, + where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + let subscription = new LiveQuerySubscription(this.requestId, query, sessionToken); + this.subscriptions.set(this.requestId, subscription); + this.requestId += 1; + this.connectPromise.then(() => { + this.socket.send(JSON.stringify(subscribeRequest)); + }); + + // adding listener so process does not crash + // best practice is for developer to register their own listener + subscription.on('error', () => {}); + + return subscription; + } + + /** + * After calling unsubscribe you'll stop receiving events from the subscription object. + * + * @method unsubscribe + * @param {Object} subscription - subscription you would like to unsubscribe from. + */ + unsubscribe(subscription) { + if (!subscription) { + return; + } + + this.subscriptions.delete(subscription.id); + let unsubscribeRequest = { + op: OP_TYPES.UNSUBSCRIBE, + requestId: subscription.id + }; + this.connectPromise.then(() => { + this.socket.send(JSON.stringify(unsubscribeRequest)); + }); + } + + /** + * After open is called, the LiveQueryClient will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ + open() { + let WebSocketImplementation = this._getWebSocketImplementation(); + if (!WebSocketImplementation) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); + return; + } + + if (this.state !== CLIENT_STATE.RECONNECTING) { + this.state = CLIENT_STATE.CONNECTING; + } + + // Get WebSocket implementation + this.socket = new WebSocketImplementation(this.serverURL); + + // Bind WebSocket callbacks + this.socket.onopen = () => { + this._handleWebSocketOpen(); + }; + + this.socket.onmessage = event => { + this._handleWebSocketMessage(event); + }; + + this.socket.onclose = () => { + this._handleWebSocketClose(); + }; + + this.socket.onerror = error => { + this._handleWebSocketError(error); + }; + } + + resubscribe() { + this.subscriptions.forEach((subscription, requestId) => { + let query = subscription.query; + let where = query.toJSON().where; + let className = query.className; + let sessionToken = subscription.sessionToken; + let subscribeRequest = { + op: OP_TYPES.SUBSCRIBE, + requestId, + query: { + className, + where + } + }; + + if (sessionToken) { + subscribeRequest.sessionToken = sessionToken; + } + + this.connectPromise.then(() => { + this.socket.send(JSON.stringify(subscribeRequest)); + }); + }); + } + + /** + * This method will close the WebSocket connection to this LiveQueryClient, + * cancel the auto reconnect and unsubscribe all subscriptions based on it. + * + * @method close + */ + close() { + if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.DISCONNECTED; + this.socket.close(); + // Notify each subscription about the close + for (let subscription of this.subscriptions.values()) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + this._handleReset(); + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + } + + _getWebSocketImplementation() { + return WebSocket; + } + + // ensure we start with valid state if connect is called again after close + _handleReset() { + this.attempts = 1;; + this.id = 0; + this.requestId = 1; + this.connectPromise = new ParsePromise(); + this.subscriptions = new Map(); + } + + _handleWebSocketOpen() { + this.attempts = 1; + let connectRequest = { + op: OP_TYPES.CONNECT, + applicationId: this.applicationId, + javascriptKey: this.javascriptKey, + masterKey: this.masterKey, + sessionToken: this.sessionToken + }; + this.socket.send(JSON.stringify(connectRequest)); + } + + _handleWebSocketMessage(event) { + let data = event.data; + if (typeof data === 'string') { + data = JSON.parse(data); + } + let subscription = null; + if (data.requestId) { + subscription = this.subscriptions.get(data.requestId); + } + switch (data.op) { + case OP_EVENTS.CONNECTED: + if (this.state === CLIENT_STATE.RECONNECTING) { + this.resubscribe(); + } + this.emit(CLIENT_EMMITER_TYPES.OPEN); + this.id = data.clientId; + this.connectPromise.resolve(); + this.state = CLIENT_STATE.CONNECTED; + break; + case OP_EVENTS.SUBSCRIBED: + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); + } + break; + case OP_EVENTS.ERROR: + if (data.requestId) { + if (subscription) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); + } + } else { + this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); + } + break; + case OP_EVENTS.UNSUBSCRIBED: + // We have already deleted subscription in unsubscribe(), do nothing here + break; + default: + // create, update, enter, leave, delete cases + let className = data.object.className; + // Delete the extrea __type and className fields during transfer to full JSON + delete data.object.__type; + delete data.object.className; + let parseObject = new ParseObject(className); + parseObject._finishFetch(data.object); + if (!subscription) { + break; + } + subscription.emit(data.op, parseObject); + } + } + + _handleWebSocketClose() { + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + this.state = CLIENT_STATE.CLOSED; + this.emit(CLIENT_EMMITER_TYPES.CLOSE); + // Notify each subscription about the close + for (let subscription of this.subscriptions.values()) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); + } + this._handleReconnect(); + } + + _handleWebSocketError(error) { + this.emit(CLIENT_EMMITER_TYPES.ERROR, error); + for (let subscription of this.subscriptions.values()) { + subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); + } + this._handleReconnect(); + } + + _handleReconnect() { + // if closed or currently reconnecting we stop attempting to reconnect + if (this.state === CLIENT_STATE.DISCONNECTED) { + return; + } + + this.state = CLIENT_STATE.RECONNECTING; + let time = generateInterval(this.attempts); + + // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. + // we're unable to distinguish different between close/error when we're unable to reconnect therefore + // we try to reonnect in both cases + // server side ws and browser WebSocket behave differently in when close/error get triggered + + if (this.reconnectHandle) { + clearTimeout(this.reconnectHandle); + } + + this.reconnectHandle = setTimeout((() => { + this.attempts++; + this.connectPromise = new ParsePromise(); + this.open(); + }).bind(this), time); + } +} \ No newline at end of file diff --git a/lib/react-native/LiveQuerySubscription.js b/lib/react-native/LiveQuerySubscription.js new file mode 100644 index 000000000..4f19b2b6e --- /dev/null +++ b/lib/react-native/LiveQuerySubscription.js @@ -0,0 +1,112 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + */ + +import EventEmitter from './EventEmitter'; +import CoreManager from './CoreManager'; + +/** + * Creates a new LiveQuery Subscription. + * Extends events.EventEmitter + * cloud functions. + * + * @constructor + * @param {string} id - subscription id + * @param {string} query - query to subscribe to + * @param {string} sessionToken - optional session token + * + *

              Open Event - When you call query.subscribe(), we send a subscribe request to + * the LiveQuery server, when we get the confirmation from the LiveQuery server, + * this event will be emitted. When the client loses WebSocket connection to the + * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we + * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, + * you'll also get this event. + * + *

              + * subscription.on('open', () => {
              + * 
              + * });

              + * + *

              Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, + * you'll get this event. The object is the ParseObject which is created. + * + *

              + * subscription.on('create', (object) => {
              + * 
              + * });

              + * + *

              Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe + * is updated (The ParseObject fulfills the ParseQuery before and after changes), + * you'll get this event. The object is the ParseObject which is updated. + * Its content is the latest value of the ParseObject. + * + *

              + * subscription.on('update', (object) => {
              + * 
              + * });

              + * + *

              Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery + * but its new value fulfills the ParseQuery, you'll get this event. The object is the + * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. + * + *

              + * subscription.on('enter', (object) => {
              + * 
              + * });

              + * + * + *

              Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value + * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject + * which leaves the ParseQuery. Its content is the latest value of the ParseObject. + * + *

              + * subscription.on('leave', (object) => {
              + * 
              + * });

              + * + * + *

              Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll + * get this event. The object is the ParseObject which is deleted. + * + *

              + * subscription.on('delete', (object) => {
              + * 
              + * });

              + * + * + *

              Close Event - When the client loses the WebSocket connection to the LiveQuery + * server and we stop receiving events, you'll get this event. + * + *

              + * subscription.on('close', () => {
              + * 
              + * });

              + * + * + */ +export default class Subscription extends EventEmitter { + constructor(id, query, sessionToken) { + super(); + this.id = id; + this.query = query; + this.sessionToken = sessionToken; + } + + /** + * @method unsubscribe + */ + unsubscribe() { + let _this = this; + CoreManager.getLiveQueryController().getDefaultLiveQueryClient().then(liveQueryClient => { + liveQueryClient.unsubscribe(_this); + _this.emit('close'); + this.resolve(); + }); + } +} \ No newline at end of file diff --git a/lib/react-native/ObjectStateMutations.js b/lib/react-native/ObjectStateMutations.js new file mode 100644 index 000000000..349dd150b --- /dev/null +++ b/lib/react-native/ObjectStateMutations.js @@ -0,0 +1,121 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import encode from './encode'; +import ParseFile from './ParseFile'; +import ParseObject from './ParseObject'; +import ParsePromise from './ParsePromise'; +import ParseRelation from './ParseRelation'; +import TaskQueue from './TaskQueue'; +import { RelationOp } from './ParseOp'; + +export function defaultState() { + return { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new TaskQueue(), + existed: false + }; +} + +export function setServerData(serverData, attributes) { + for (let attr in attributes) { + if (typeof attributes[attr] !== 'undefined') { + serverData[attr] = attributes[attr]; + } else { + delete serverData[attr]; + } + } +} + +export function setPendingOp(pendingOps, attr, op) { + let last = pendingOps.length - 1; + if (op) { + pendingOps[last][attr] = op; + } else { + delete pendingOps[last][attr]; + } +} + +export function pushPendingState(pendingOps) { + pendingOps.push({}); +} + +export function popPendingState(pendingOps) { + let first = pendingOps.shift(); + if (!pendingOps.length) { + pendingOps[0] = {}; + } + return first; +} + +export function mergeFirstPendingState(pendingOps) { + let first = popPendingState(pendingOps); + let next = pendingOps[0]; + for (let attr in first) { + if (next[attr] && first[attr]) { + let merged = next[attr].mergeWith(first[attr]); + if (merged) { + next[attr] = merged; + } + } else { + next[attr] = first[attr]; + } + } +} + +export function estimateAttribute(serverData, pendingOps, className, id, attr) { + let value = serverData[attr]; + for (let i = 0; i < pendingOps.length; i++) { + if (pendingOps[i][attr]) { + if (pendingOps[i][attr] instanceof RelationOp) { + if (id) { + value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); + } + } else { + value = pendingOps[i][attr].applyTo(value); + } + } + } + return value; +} + +export function estimateAttributes(serverData, pendingOps, className, id) { + let data = {}; + + for (var attr in serverData) { + data[attr] = serverData[attr]; + } + for (let i = 0; i < pendingOps.length; i++) { + for (attr in pendingOps[i]) { + if (pendingOps[i][attr] instanceof RelationOp) { + if (id) { + data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); + } + } else { + data[attr] = pendingOps[i][attr].applyTo(data[attr]); + } + } + } + return data; +} + +export function commitServerChanges(serverData, objectCache, changes) { + for (let attr in changes) { + let val = changes[attr]; + serverData[attr] = val; + if (val && typeof val === 'object' && !(val instanceof ParseObject) && !(val instanceof ParseFile) && !(val instanceof ParseRelation)) { + let json = encode(val, false, true); + objectCache[attr] = JSON.stringify(json); + } + } +} \ No newline at end of file diff --git a/lib/react-native/Parse.js b/lib/react-native/Parse.js new file mode 100644 index 000000000..b95835026 --- /dev/null +++ b/lib/react-native/Parse.js @@ -0,0 +1,141 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import decode from './decode'; +import encode from './encode'; +import CoreManager from './CoreManager'; +import InstallationController from './InstallationController'; +import * as ParseOp from './ParseOp'; +import RESTController from './RESTController'; + +/** + * Contains all Parse API classes and functions. + * @class Parse + * @static + */ +var Parse = { + /** + * Call this method first to set up your authentication tokens for Parse. + * You can get your keys from the Data Browser on parse.com. + * @method initialize + * @param {String} applicationId Your Parse Application ID. + * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) + * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) + * @static + */ + initialize(applicationId, javaScriptKey) { + Parse._initialize(applicationId, javaScriptKey); + }, + + _initialize(applicationId, javaScriptKey, masterKey) { + CoreManager.set('APPLICATION_ID', applicationId); + CoreManager.set('JAVASCRIPT_KEY', javaScriptKey); + CoreManager.set('MASTER_KEY', masterKey); + CoreManager.set('USE_MASTER_KEY', false); + } +}; + +/** These legacy setters may eventually be deprecated **/ +Object.defineProperty(Parse, 'applicationId', { + get() { + return CoreManager.get('APPLICATION_ID'); + }, + set(value) { + CoreManager.set('APPLICATION_ID', value); + } +}); +Object.defineProperty(Parse, 'javaScriptKey', { + get() { + return CoreManager.get('JAVASCRIPT_KEY'); + }, + set(value) { + CoreManager.set('JAVASCRIPT_KEY', value); + } +}); +Object.defineProperty(Parse, 'masterKey', { + get() { + return CoreManager.get('MASTER_KEY'); + }, + set(value) { + CoreManager.set('MASTER_KEY', value); + } +}); +Object.defineProperty(Parse, 'serverURL', { + get() { + return CoreManager.get('SERVER_URL'); + }, + set(value) { + CoreManager.set('SERVER_URL', value); + } +}); +Object.defineProperty(Parse, 'liveQueryServerURL', { + get() { + return CoreManager.get('LIVEQUERY_SERVER_URL'); + }, + set(value) { + CoreManager.set('LIVEQUERY_SERVER_URL', value); + } +}); +/** End setters **/ + +Parse.ACL = require('./ParseACL').default; +Parse.Analytics = require('./Analytics'); +Parse.Cloud = require('./Cloud'); +Parse.CoreManager = require('./CoreManager'); +Parse.Config = require('./ParseConfig').default; +Parse.Error = require('./ParseError').default; +Parse.FacebookUtils = require('./FacebookUtils').default; +Parse.File = require('./ParseFile').default; +Parse.GeoPoint = require('./ParseGeoPoint').default; +Parse.Installation = require('./ParseInstallation').default; +Parse.Object = require('./ParseObject').default; +Parse.Op = { + Set: ParseOp.SetOp, + Unset: ParseOp.UnsetOp, + Increment: ParseOp.IncrementOp, + Add: ParseOp.AddOp, + Remove: ParseOp.RemoveOp, + AddUnique: ParseOp.AddUniqueOp, + Relation: ParseOp.RelationOp +}; +Parse.Promise = require('./ParsePromise').default; +Parse.Push = require('./Push'); +Parse.Query = require('./ParseQuery').default; +Parse.Relation = require('./ParseRelation').default; +Parse.Role = require('./ParseRole').default; +Parse.Session = require('./ParseSession').default; +Parse.Storage = require('./Storage'); +Parse.User = require('./ParseUser').default; +Parse.LiveQuery = require('./ParseLiveQuery').default; +Parse.LiveQueryClient = require('./LiveQueryClient').default; + +Parse._request = function (...args) { + return CoreManager.getRESTController().request.apply(null, args); +}; +Parse._ajax = function (...args) { + return CoreManager.getRESTController().ajax.apply(null, args); +}; +// We attempt to match the signatures of the legacy versions of these methods +Parse._decode = function (_, value) { + return decode(value); +}; +Parse._encode = function (value, _, disallowObjects) { + return encode(value, disallowObjects); +}; +Parse._getInstallationId = function () { + return CoreManager.getInstallationController().currentInstallationId(); +}; + +CoreManager.setInstallationController(InstallationController); +CoreManager.setRESTController(RESTController); + +// For legacy requires, of the form `var Parse = require('parse').Parse` +Parse.Parse = Parse; + +module.exports = Parse; \ No newline at end of file diff --git a/lib/react-native/ParseACL.js b/lib/react-native/ParseACL.js new file mode 100644 index 000000000..2c28c6fa6 --- /dev/null +++ b/lib/react-native/ParseACL.js @@ -0,0 +1,325 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseRole from './ParseRole'; +import ParseUser from './ParseUser'; + +var PUBLIC_KEY = '*'; + +/** + * Creates a new ACL. + * If no argument is given, the ACL has no permissions for anyone. + * If the argument is a Parse.User, the ACL will have read and write + * permission for only that user. + * If the argument is any other JSON object, that object will be interpretted + * as a serialized ACL created with toJSON(). + * @class Parse.ACL + * @constructor + * + *

              An ACL, or Access Control List can be added to any + * Parse.Object to restrict access to only a subset of users + * of your application.

              + */ +export default class ParseACL { + + constructor(arg1) { + this.permissionsById = {}; + if (arg1 && typeof arg1 === 'object') { + if (arg1 instanceof ParseUser) { + this.setReadAccess(arg1, true); + this.setWriteAccess(arg1, true); + } else { + for (var userId in arg1) { + var accessList = arg1[userId]; + if (typeof userId !== 'string') { + throw new TypeError('Tried to create an ACL with an invalid user id.'); + } + this.permissionsById[userId] = {}; + for (var permission in accessList) { + var allowed = accessList[permission]; + if (permission !== 'read' && permission !== 'write') { + throw new TypeError('Tried to create an ACL with an invalid permission type.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('Tried to create an ACL with an invalid permission value.'); + } + this.permissionsById[userId][permission] = allowed; + } + } + } + } else if (typeof arg1 === 'function') { + throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); + } + } + + /** + * Returns a JSON-encoded version of the ACL. + * @method toJSON + * @return {Object} + */ + toJSON() { + var permissions = {}; + for (var p in this.permissionsById) { + permissions[p] = this.permissionsById[p]; + } + return permissions; + } + + /** + * Returns whether this ACL is equal to another object + * @method equals + * @param other The other object to compare to + * @return {Boolean} + */ + equals(other) { + if (!(other instanceof ParseACL)) { + return false; + } + var users = Object.keys(this.permissionsById); + var otherUsers = Object.keys(other.permissionsById); + if (users.length !== otherUsers.length) { + return false; + } + for (var u in this.permissionsById) { + if (!other.permissionsById[u]) { + return false; + } + if (this.permissionsById[u].read !== other.permissionsById[u].read) { + return false; + } + if (this.permissionsById[u].write !== other.permissionsById[u].write) { + return false; + } + } + return true; + } + + _setAccess(accessType, userId, allowed) { + if (userId instanceof ParseUser) { + userId = userId.id; + } else if (userId instanceof ParseRole) { + const name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + if (typeof userId !== 'string') { + throw new TypeError('userId must be a string.'); + } + if (typeof allowed !== 'boolean') { + throw new TypeError('allowed must be either true or false.'); + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + if (!allowed) { + // The user already doesn't have this permission, so no action is needed + return; + } else { + permissions = {}; + this.permissionsById[userId] = permissions; + } + } + + if (allowed) { + this.permissionsById[userId][accessType] = true; + } else { + delete permissions[accessType]; + if (Object.keys(permissions).length === 0) { + delete this.permissionsById[userId]; + } + } + } + + _getAccess(accessType, userId) { + if (userId instanceof ParseUser) { + userId = userId.id; + if (!userId) { + throw new Error('Cannot get access for a ParseUser without an ID'); + } + } else if (userId instanceof ParseRole) { + const name = userId.getName(); + if (!name) { + throw new TypeError('Role must have a name'); + } + userId = 'role:' + name; + } + var permissions = this.permissionsById[userId]; + if (!permissions) { + return false; + } + return !!permissions[accessType]; + } + + /** + * Sets whether the given user is allowed to read this object. + * @method setReadAccess + * @param userId An instance of Parse.User or its objectId. + * @param {Boolean} allowed Whether that user should have read access. + */ + setReadAccess(userId, allowed) { + this._setAccess('read', userId, allowed); + } + + /** + * Get whether the given user id is *explicitly* allowed to read this object. + * Even if this returns false, the user may still be able to access it if + * getPublicReadAccess returns true or a role that the user belongs to has + * write access. + * @method getReadAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + getReadAccess(userId) { + return this._getAccess('read', userId); + } + + /** + * Sets whether the given user id is allowed to write this object. + * @method setWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. + * @param {Boolean} allowed Whether that user should have write access. + */ + setWriteAccess(userId, allowed) { + this._setAccess('write', userId, allowed); + } + + /** + * Gets whether the given user id is *explicitly* allowed to write this object. + * Even if this returns false, the user may still be able to write it if + * getPublicWriteAccess returns true or a role that the user belongs to has + * write access. + * @method getWriteAccess + * @param userId An instance of Parse.User or its objectId, or a Parse.Role. + * @return {Boolean} + */ + getWriteAccess(userId) { + return this._getAccess('write', userId); + } + + /** + * Sets whether the public is allowed to read this object. + * @method setPublicReadAccess + * @param {Boolean} allowed + */ + setPublicReadAccess(allowed) { + this.setReadAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to read this object. + * @method getPublicReadAccess + * @return {Boolean} + */ + getPublicReadAccess() { + return this.getReadAccess(PUBLIC_KEY); + } + + /** + * Sets whether the public is allowed to write this object. + * @method setPublicWriteAccess + * @param {Boolean} allowed + */ + setPublicWriteAccess(allowed) { + this.setWriteAccess(PUBLIC_KEY, allowed); + } + + /** + * Gets whether the public is allowed to write this object. + * @method getPublicWriteAccess + * @return {Boolean} + */ + getPublicWriteAccess() { + return this.getWriteAccess(PUBLIC_KEY); + } + + /** + * Gets whether users belonging to the given role are allowed + * to read this object. Even if this returns false, the role may + * still be able to write it if a parent role has read access. + * + * @method getRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has read access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + getRoleReadAccess(role) { + if (role instanceof ParseRole) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getReadAccess('role:' + role); + } + + /** + * Gets whether users belonging to the given role are allowed + * to write this object. Even if this returns false, the role may + * still be able to write it if a parent role has write access. + * + * @method getRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @return {Boolean} true if the role has write access. false otherwise. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + getRoleWriteAccess(role) { + if (role instanceof ParseRole) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + return this.getWriteAccess('role:' + role); + } + + /** + * Sets whether users belonging to the given role are allowed + * to read this object. + * + * @method setRoleReadAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can read this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + setRoleReadAccess(role, allowed) { + if (role instanceof ParseRole) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setReadAccess('role:' + role, allowed); + } + + /** + * Sets whether users belonging to the given role are allowed + * to write this object. + * + * @method setRoleWriteAccess + * @param role The name of the role, or a Parse.Role object. + * @param {Boolean} allowed Whether the given role can write this object. + * @throws {TypeError} If role is neither a Parse.Role nor a String. + */ + setRoleWriteAccess(role, allowed) { + if (role instanceof ParseRole) { + // Normalize to the String name + role = role.getName(); + } + if (typeof role !== 'string') { + throw new TypeError('role must be a ParseRole or a String'); + } + this.setWriteAccess('role:' + role, allowed); + } +} \ No newline at end of file diff --git a/lib/react-native/ParseConfig.js b/lib/react-native/ParseConfig.js new file mode 100644 index 000000000..ce6cbdb45 --- /dev/null +++ b/lib/react-native/ParseConfig.js @@ -0,0 +1,168 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import decode from './decode'; +import encode from './encode'; +import escape from './escape'; +import ParseError from './ParseError'; +import ParsePromise from './ParsePromise'; +import Storage from './Storage'; + +/** + * Parse.Config is a local representation of configuration data that + * can be set from the Parse dashboard. + * + * @class Parse.Config + * @constructor + */ + +export default class ParseConfig { + + constructor() { + this.attributes = {}; + this._escapedAttributes = {}; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The name of an attribute. + */ + get(attr) { + return this.attributes[attr]; + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The name of an attribute. + */ + escape(attr) { + var html = this._escapedAttributes[attr]; + if (html) { + return html; + } + var val = this.attributes[attr]; + var escaped = ''; + if (val != null) { + escaped = escape(val.toString()); + } + this._escapedAttributes[attr] = escaped; + return escaped; + } + + /** + * Retrieves the most recently-fetched configuration object, either from + * memory or from local storage if necessary. + * + * @method current + * @static + * @return {Config} The most recently-fetched Parse.Config if it + * exists, else an empty Parse.Config. + */ + static current() { + var controller = CoreManager.getConfigController(); + return controller.current(); + } + + /** + * Gets a new configuration object from the server. + * @method get + * @static + * @param {Object} options A Backbone-style options object. + * Valid options are:
                + *
              • success: Function to call when the get completes successfully. + *
              • error: Function to call when the get fails. + *
              + * @return {Parse.Promise} A promise that is resolved with a newly-created + * configuration object when the get completes. + */ + static get(options) { + options = options || {}; + + var controller = CoreManager.getConfigController(); + return controller.get()._thenRunCallbacks(options); + } +} + +var currentConfig = null; + +var CURRENT_CONFIG_KEY = 'currentConfig'; + +function decodePayload(data) { + try { + var json = JSON.parse(data); + if (json && typeof json === 'object') { + return decode(json); + } + } catch (e) { + return null; + } +} + +var DefaultController = { + current() { + if (currentConfig) { + return currentConfig; + } + + var config = new ParseConfig(); + var storagePath = Storage.generatePath(CURRENT_CONFIG_KEY); + var configData; + if (!Storage.async()) { + configData = Storage.getItem(storagePath); + + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + } + // Return a promise for async storage controllers + return Storage.getItemAsync(storagePath).then(configData => { + if (configData) { + var attributes = decodePayload(configData); + if (attributes) { + config.attributes = attributes; + currentConfig = config; + } + } + return config; + }); + }, + + get() { + var RESTController = CoreManager.getRESTController(); + + return RESTController.request('GET', 'config', {}, {}).then(response => { + if (!response || !response.params) { + var error = new ParseError(ParseError.INVALID_JSON, 'Config JSON response invalid.'); + return ParsePromise.error(error); + } + + var config = new ParseConfig(); + config.attributes = {}; + for (var attr in response.params) { + config.attributes[attr] = decode(response.params[attr]); + } + currentConfig = config; + return Storage.setItemAsync(Storage.generatePath(CURRENT_CONFIG_KEY), JSON.stringify(response.params)).then(() => { + return config; + }); + }); + } +}; + +CoreManager.setConfigController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseError.js b/lib/react-native/ParseError.js new file mode 100644 index 000000000..a5bb24bc7 --- /dev/null +++ b/lib/react-native/ParseError.js @@ -0,0 +1,491 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +/** + * Constructs a new Parse.Error object with the given code and message. + * @class Parse.Error + * @constructor + * @param {Number} code An error code constant from Parse.Error. + * @param {String} message A detailed description of the error. + */ +export default class ParseError { + constructor(code, message) { + this.code = code; + this.message = message; + } +} + +/** + * Error code indicating some error other than those enumerated here. + * @property OTHER_CAUSE + * @static + * @final + */ +ParseError.OTHER_CAUSE = -1; + +/** + * Error code indicating that something has gone wrong with the server. + * If you get this error code, it is Parse's fault. Contact us at + * https://parse.com/help + * @property INTERNAL_SERVER_ERROR + * @static + * @final + */ +ParseError.INTERNAL_SERVER_ERROR = 1; + +/** + * Error code indicating the connection to the Parse servers failed. + * @property CONNECTION_FAILED + * @static + * @final + */ +ParseError.CONNECTION_FAILED = 100; + +/** + * Error code indicating the specified object doesn't exist. + * @property OBJECT_NOT_FOUND + * @static + * @final + */ +ParseError.OBJECT_NOT_FOUND = 101; + +/** + * Error code indicating you tried to query with a datatype that doesn't + * support it, like exact matching an array or object. + * @property INVALID_QUERY + * @static + * @final + */ +ParseError.INVALID_QUERY = 102; + +/** + * Error code indicating a missing or invalid classname. Classnames are + * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the + * only valid characters. + * @property INVALID_CLASS_NAME + * @static + * @final + */ +ParseError.INVALID_CLASS_NAME = 103; + +/** + * Error code indicating an unspecified object id. + * @property MISSING_OBJECT_ID + * @static + * @final + */ +ParseError.MISSING_OBJECT_ID = 104; + +/** + * Error code indicating an invalid key name. Keys are case-sensitive. They + * must start with a letter, and a-zA-Z0-9_ are the only valid characters. + * @property INVALID_KEY_NAME + * @static + * @final + */ +ParseError.INVALID_KEY_NAME = 105; + +/** + * Error code indicating a malformed pointer. You should not see this unless + * you have been mucking about changing internal Parse code. + * @property INVALID_POINTER + * @static + * @final + */ +ParseError.INVALID_POINTER = 106; + +/** + * Error code indicating that badly formed JSON was received upstream. This + * either indicates you have done something unusual with modifying how + * things encode to JSON, or the network is failing badly. + * @property INVALID_JSON + * @static + * @final + */ +ParseError.INVALID_JSON = 107; + +/** + * Error code indicating that the feature you tried to access is only + * available internally for testing purposes. + * @property COMMAND_UNAVAILABLE + * @static + * @final + */ +ParseError.COMMAND_UNAVAILABLE = 108; + +/** + * You must call Parse.initialize before using the Parse library. + * @property NOT_INITIALIZED + * @static + * @final + */ +ParseError.NOT_INITIALIZED = 109; + +/** + * Error code indicating that a field was set to an inconsistent type. + * @property INCORRECT_TYPE + * @static + * @final + */ +ParseError.INCORRECT_TYPE = 111; + +/** + * Error code indicating an invalid channel name. A channel name is either + * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ + * characters and starts with a letter. + * @property INVALID_CHANNEL_NAME + * @static + * @final + */ +ParseError.INVALID_CHANNEL_NAME = 112; + +/** + * Error code indicating that push is misconfigured. + * @property PUSH_MISCONFIGURED + * @static + * @final + */ +ParseError.PUSH_MISCONFIGURED = 115; + +/** + * Error code indicating that the object is too large. + * @property OBJECT_TOO_LARGE + * @static + * @final + */ +ParseError.OBJECT_TOO_LARGE = 116; + +/** + * Error code indicating that the operation isn't allowed for clients. + * @property OPERATION_FORBIDDEN + * @static + * @final + */ +ParseError.OPERATION_FORBIDDEN = 119; + +/** + * Error code indicating the result was not found in the cache. + * @property CACHE_MISS + * @static + * @final + */ +ParseError.CACHE_MISS = 120; + +/** + * Error code indicating that an invalid key was used in a nested + * JSONObject. + * @property INVALID_NESTED_KEY + * @static + * @final + */ +ParseError.INVALID_NESTED_KEY = 121; + +/** + * Error code indicating that an invalid filename was used for ParseFile. + * A valid file name contains only a-zA-Z0-9_. characters and is between 1 + * and 128 characters. + * @property INVALID_FILE_NAME + * @static + * @final + */ +ParseError.INVALID_FILE_NAME = 122; + +/** + * Error code indicating an invalid ACL was provided. + * @property INVALID_ACL + * @static + * @final + */ +ParseError.INVALID_ACL = 123; + +/** + * Error code indicating that the request timed out on the server. Typically + * this indicates that the request is too expensive to run. + * @property TIMEOUT + * @static + * @final + */ +ParseError.TIMEOUT = 124; + +/** + * Error code indicating that the email address was invalid. + * @property INVALID_EMAIL_ADDRESS + * @static + * @final + */ +ParseError.INVALID_EMAIL_ADDRESS = 125; + +/** + * Error code indicating a missing content type. + * @property MISSING_CONTENT_TYPE + * @static + * @final + */ +ParseError.MISSING_CONTENT_TYPE = 126; + +/** + * Error code indicating a missing content length. + * @property MISSING_CONTENT_LENGTH + * @static + * @final + */ +ParseError.MISSING_CONTENT_LENGTH = 127; + +/** + * Error code indicating an invalid content length. + * @property INVALID_CONTENT_LENGTH + * @static + * @final + */ +ParseError.INVALID_CONTENT_LENGTH = 128; + +/** + * Error code indicating a file that was too large. + * @property FILE_TOO_LARGE + * @static + * @final + */ +ParseError.FILE_TOO_LARGE = 129; + +/** + * Error code indicating an error saving a file. + * @property FILE_SAVE_ERROR + * @static + * @final + */ +ParseError.FILE_SAVE_ERROR = 130; + +/** + * Error code indicating that a unique field was given a value that is + * already taken. + * @property DUPLICATE_VALUE + * @static + * @final + */ +ParseError.DUPLICATE_VALUE = 137; + +/** + * Error code indicating that a role's name is invalid. + * @property INVALID_ROLE_NAME + * @static + * @final + */ +ParseError.INVALID_ROLE_NAME = 139; + +/** + * Error code indicating that an application quota was exceeded. Upgrade to + * resolve. + * @property EXCEEDED_QUOTA + * @static + * @final + */ +ParseError.EXCEEDED_QUOTA = 140; + +/** + * Error code indicating that a Cloud Code script failed. + * @property SCRIPT_FAILED + * @static + * @final + */ +ParseError.SCRIPT_FAILED = 141; + +/** + * Error code indicating that a Cloud Code validation failed. + * @property VALIDATION_ERROR + * @static + * @final + */ +ParseError.VALIDATION_ERROR = 142; + +/** + * Error code indicating that invalid image data was provided. + * @property INVALID_IMAGE_DATA + * @static + * @final + */ +ParseError.INVALID_IMAGE_DATA = 143; + +/** + * Error code indicating an unsaved file. + * @property UNSAVED_FILE_ERROR + * @static + * @final + */ +ParseError.UNSAVED_FILE_ERROR = 151; + +/** + * Error code indicating an invalid push time. + * @property INVALID_PUSH_TIME_ERROR + * @static + * @final + */ +ParseError.INVALID_PUSH_TIME_ERROR = 152; + +/** + * Error code indicating an error deleting a file. + * @property FILE_DELETE_ERROR + * @static + * @final + */ +ParseError.FILE_DELETE_ERROR = 153; + +/** + * Error code indicating that the application has exceeded its request + * limit. + * @property REQUEST_LIMIT_EXCEEDED + * @static + * @final + */ +ParseError.REQUEST_LIMIT_EXCEEDED = 155; + +/** + * Error code indicating an invalid event name. + * @property INVALID_EVENT_NAME + * @static + * @final + */ +ParseError.INVALID_EVENT_NAME = 160; + +/** + * Error code indicating that the username is missing or empty. + * @property USERNAME_MISSING + * @static + * @final + */ +ParseError.USERNAME_MISSING = 200; + +/** + * Error code indicating that the password is missing or empty. + * @property PASSWORD_MISSING + * @static + * @final + */ +ParseError.PASSWORD_MISSING = 201; + +/** + * Error code indicating that the username has already been taken. + * @property USERNAME_TAKEN + * @static + * @final + */ +ParseError.USERNAME_TAKEN = 202; + +/** + * Error code indicating that the email has already been taken. + * @property EMAIL_TAKEN + * @static + * @final + */ +ParseError.EMAIL_TAKEN = 203; + +/** + * Error code indicating that the email is missing, but must be specified. + * @property EMAIL_MISSING + * @static + * @final + */ +ParseError.EMAIL_MISSING = 204; + +/** + * Error code indicating that a user with the specified email was not found. + * @property EMAIL_NOT_FOUND + * @static + * @final + */ +ParseError.EMAIL_NOT_FOUND = 205; + +/** + * Error code indicating that a user object without a valid session could + * not be altered. + * @property SESSION_MISSING + * @static + * @final + */ +ParseError.SESSION_MISSING = 206; + +/** + * Error code indicating that a user can only be created through signup. + * @property MUST_CREATE_USER_THROUGH_SIGNUP + * @static + * @final + */ +ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; + +/** + * Error code indicating that an an account being linked is already linked + * to another user. + * @property ACCOUNT_ALREADY_LINKED + * @static + * @final + */ +ParseError.ACCOUNT_ALREADY_LINKED = 208; + +/** + * Error code indicating that the current session token is invalid. + * @property INVALID_SESSION_TOKEN + * @static + * @final + */ +ParseError.INVALID_SESSION_TOKEN = 209; + +/** + * Error code indicating that a user cannot be linked to an account because + * that account's id could not be found. + * @property LINKED_ID_MISSING + * @static + * @final + */ +ParseError.LINKED_ID_MISSING = 250; + +/** + * Error code indicating that a user with a linked (e.g. Facebook) account + * has an invalid session. + * @property INVALID_LINKED_SESSION + * @static + * @final + */ +ParseError.INVALID_LINKED_SESSION = 251; + +/** + * Error code indicating that a service being linked (e.g. Facebook or + * Twitter) is unsupported. + * @property UNSUPPORTED_SERVICE + * @static + * @final + */ +ParseError.UNSUPPORTED_SERVICE = 252; + +/** + * Error code indicating that there were multiple errors. Aggregate errors + * have an "errors" property, which is an array of error objects with more + * detail about each error that occurred. + * @property AGGREGATE_ERROR + * @static + * @final + */ +ParseError.AGGREGATE_ERROR = 600; + +/** + * Error code indicating the client was unable to read an input file. + * @property FILE_READ_ERROR + * @static + * @final + */ +ParseError.FILE_READ_ERROR = 601; + +/** + * Error code indicating a real error code is unavailable because + * we had to use an XDomainRequest object to allow CORS requests in + * Internet Explorer, which strips the body from HTTP responses that have + * a non-2XX status code. + * @property X_DOMAIN_REQUEST + * @static + * @final + */ +ParseError.X_DOMAIN_REQUEST = 602; \ No newline at end of file diff --git a/lib/react-native/ParseFile.js b/lib/react-native/ParseFile.js new file mode 100644 index 000000000..0b1b448a8 --- /dev/null +++ b/lib/react-native/ParseFile.js @@ -0,0 +1,247 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import ParsePromise from './ParsePromise'; + +var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; + +function b64Digit(number) { + if (number < 26) { + return String.fromCharCode(65 + number); + } + if (number < 52) { + return String.fromCharCode(97 + (number - 26)); + } + if (number < 62) { + return String.fromCharCode(48 + (number - 52)); + } + if (number === 62) { + return '+'; + } + if (number === 63) { + return '/'; + } + throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); +} + +/** + * A Parse.File is a local representation of a file that is saved to the Parse + * cloud. + * @class Parse.File + * @constructor + * @param name {String} The file's name. This will be prefixed by a unique + * value once the file has finished saving. The file name must begin with + * an alphanumeric character, and consist of alphanumeric characters, + * periods, spaces, underscores, or dashes. + * @param data {Array} The data for the file, as either: + * 1. an Array of byte value Numbers, or + * 2. an Object like { base64: "..." } with a base64-encoded String. + * 3. a File object selected with a file upload control. (3) only works + * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. + * For example:
              + * var fileUploadControl = $("#profilePhotoFileUpload")[0];
              + * if (fileUploadControl.files.length > 0) {
              + *   var file = fileUploadControl.files[0];
              + *   var name = "photo.jpg";
              + *   var parseFile = new Parse.File(name, file);
              + *   parseFile.save().then(function() {
              + *     // The file has been saved to Parse.
              + *   }, function(error) {
              + *     // The file either could not be read, or could not be saved to Parse.
              + *   });
              + * }
              + * @param type {String} Optional Content-Type header to use for the file. If + * this is omitted, the content type will be inferred from the name's + * extension. + */ +export default class ParseFile { + + constructor(name, data, type) { + var specifiedType = type || ''; + + this._name = name; + + if (data !== undefined) { + if (Array.isArray(data)) { + this._source = { + format: 'base64', + base64: ParseFile.encodeBase64(data), + type: specifiedType + }; + } else if (typeof File !== 'undefined' && data instanceof File) { + this._source = { + format: 'file', + file: data, + type: specifiedType + }; + } else if (data && typeof data.base64 === 'string') { + const base64 = data.base64; + var commaIndex = base64.indexOf(','); + + if (commaIndex !== -1) { + var matches = dataUriRegexp.exec(base64.slice(0, commaIndex + 1)); + // if data URI with type and charset, there will be 4 matches. + this._source = { + format: 'base64', + base64: base64.slice(commaIndex + 1), + type: matches[1] + }; + } else { + this._source = { + format: 'base64', + base64: base64, + type: specifiedType + }; + } + } else { + throw new TypeError('Cannot create a Parse.File with that data.'); + } + } + } + + /** + * Gets the name of the file. Before save is called, this is the filename + * given by the user. After save is called, that name gets prefixed with a + * unique identifier. + * @method name + * @return {String} + */ + name() { + return this._name; + } + + /** + * Gets the url of the file. It is only available after you save the file or + * after you get the file from a Parse.Object. + * @method url + * @param {Object} options An object to specify url options + * @return {String} + */ + url(options) { + options = options || {}; + if (!this._url) { + return; + } + if (options.forceSecure) { + return this._url.replace(/^http:\/\//i, 'https://'); + } else { + return this._url; + } + } + + /** + * Saves the file to the Parse cloud. + * @method save + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} Promise that is resolved when the save finishes. + */ + save(options) { + options = options || {}; + var controller = CoreManager.getFileController(); + if (!this._previousSave) { + if (this._source.format === 'file') { + this._previousSave = controller.saveFile(this._name, this._source).then(res => { + this._name = res.name; + this._url = res.url; + return this; + }); + } else { + this._previousSave = controller.saveBase64(this._name, this._source).then(res => { + this._name = res.name; + this._url = res.url; + return this; + }); + } + } + if (this._previousSave) { + return this._previousSave._thenRunCallbacks(options); + } + } + + toJSON() { + return { + __type: 'File', + name: this._name, + url: this._url + }; + } + + equals(other) { + if (this === other) { + return true; + } + // Unsaved Files are never equal, since they will be saved to different URLs + return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; + } + + static fromJSON(obj) { + if (obj.__type !== 'File') { + throw new TypeError('JSON object does not represent a ParseFile'); + } + var file = new ParseFile(obj.name); + file._url = obj.url; + return file; + } + + static encodeBase64(bytes) { + var chunks = []; + chunks.length = Math.ceil(bytes.length / 3); + for (var i = 0; i < chunks.length; i++) { + var b1 = bytes[i * 3]; + var b2 = bytes[i * 3 + 1] || 0; + var b3 = bytes[i * 3 + 2] || 0; + + var has2 = i * 3 + 1 < bytes.length; + var has3 = i * 3 + 2 < bytes.length; + + chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); + } + + return chunks.join(''); + } +} + +var DefaultController = { + saveFile: function (name, source) { + if (source.format !== 'file') { + throw new Error('saveFile can only be used with File-type sources.'); + } + // To directly upload a File, we use a REST-style AJAX request + var headers = { + 'X-Parse-Application-ID': CoreManager.get('APPLICATION_ID'), + 'X-Parse-JavaScript-Key': CoreManager.get('JAVASCRIPT_KEY'), + 'Content-Type': source.type || (source.file ? source.file.type : null) + }; + var url = CoreManager.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += 'files/' + name; + return CoreManager.getRESTController().ajax('POST', url, source.file, headers); + }, + + saveBase64: function (name, source) { + if (source.format !== 'base64') { + throw new Error('saveBase64 can only be used with Base64-type sources.'); + } + var data = { + base64: source.base64 + }; + if (source.type) { + data._ContentType = source.type; + } + + return CoreManager.getRESTController().request('POST', 'files/' + name, data); + } +}; + +CoreManager.setFileController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseGeoPoint.js b/lib/react-native/ParseGeoPoint.js new file mode 100644 index 000000000..e6dcddf43 --- /dev/null +++ b/lib/react-native/ParseGeoPoint.js @@ -0,0 +1,186 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParsePromise from './ParsePromise'; + +/** + * Creates a new GeoPoint with any of the following forms:
              + *
              + *   new GeoPoint(otherGeoPoint)
              + *   new GeoPoint(30, 30)
              + *   new GeoPoint([30, 30])
              + *   new GeoPoint({latitude: 30, longitude: 30})
              + *   new GeoPoint()  // defaults to (0, 0)
              + *   
              + * @class Parse.GeoPoint + * @constructor + * + *

              Represents a latitude / longitude point that may be associated + * with a key in a ParseObject or used as a reference point for geo queries. + * This allows proximity-based queries on the key.

              + * + *

              Only one key in a class may contain a GeoPoint.

              + * + *

              Example:

              + *   var point = new Parse.GeoPoint(30.0, -20.0);
              + *   var object = new Parse.Object("PlaceObject");
              + *   object.set("location", point);
              + *   object.save();

              + */ +export default class ParseGeoPoint { + + constructor(arg1, arg2) { + if (Array.isArray(arg1)) { + ParseGeoPoint._validate(arg1[0], arg1[1]); + this._latitude = arg1[0]; + this._longitude = arg1[1]; + } else if (typeof arg1 === 'object') { + ParseGeoPoint._validate(arg1.latitude, arg1.longitude); + this._latitude = arg1.latitude; + this._longitude = arg1.longitude; + } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { + ParseGeoPoint._validate(arg1, arg2); + this._latitude = arg1; + this._longitude = arg2; + } else { + this._latitude = 0; + this._longitude = 0; + } + } + + /** + * North-south portion of the coordinate, in range [-90, 90]. + * Throws an exception if set out of range in a modern browser. + * @property latitude + * @type Number + */ + get latitude() { + return this._latitude; + } + + set latitude(val) { + ParseGeoPoint._validate(val, this.longitude); + this._latitude = val; + } + + /** + * East-west portion of the coordinate, in range [-180, 180]. + * Throws if set out of range in a modern browser. + * @property longitude + * @type Number + */ + get longitude() { + return this._longitude; + } + + set longitude(val) { + ParseGeoPoint._validate(this.latitude, val); + this._longitude = val; + } + + /** + * Returns a JSON representation of the GeoPoint, suitable for Parse. + * @method toJSON + * @return {Object} + */ + toJSON() { + ParseGeoPoint._validate(this._latitude, this._longitude); + return { + __type: 'GeoPoint', + latitude: this._latitude, + longitude: this._longitude + }; + } + + equals(other) { + return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; + } + + /** + * Returns the distance from this GeoPoint to another in radians. + * @method radiansTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + radiansTo(point) { + var d2r = Math.PI / 180.0; + var lat1rad = this.latitude * d2r; + var long1rad = this.longitude * d2r; + var lat2rad = point.latitude * d2r; + var long2rad = point.longitude * d2r; + + var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); + var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); + // Square of half the straight line chord distance between both points. + var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; + a = Math.min(1.0, a); + return 2 * Math.asin(Math.sqrt(a)); + } + + /** + * Returns the distance from this GeoPoint to another in kilometers. + * @method kilometersTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + kilometersTo(point) { + return this.radiansTo(point) * 6371.0; + } + + /** + * Returns the distance from this GeoPoint to another in miles. + * @method milesTo + * @param {Parse.GeoPoint} point the other Parse.GeoPoint. + * @return {Number} + */ + milesTo(point) { + return this.radiansTo(point) * 3958.8; + } + + /** + * Throws an exception if the given lat-long is out of bounds. + */ + static _validate(latitude, longitude) { + if (latitude !== latitude || longitude !== longitude) { + throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); + } + if (latitude < -90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); + } + if (latitude > 90.0) { + throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); + } + if (longitude < -180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); + } + if (longitude > 180.0) { + throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); + } + } + + /** + * Creates a GeoPoint with the user's current location, if available. + * Calls options.success with a new GeoPoint instance or calls options.error. + * @method current + * @param {Object} options An object with success and error callbacks. + * @static + */ + static current(options) { + var promise = new ParsePromise(); + navigator.geolocation.getCurrentPosition(function (location) { + promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); + }, function (error) { + promise.reject(error); + }); + + return promise._thenRunCallbacks(options); + } +} \ No newline at end of file diff --git a/lib/react-native/ParseHooks.js b/lib/react-native/ParseHooks.js new file mode 100644 index 000000000..e079fcd51 --- /dev/null +++ b/lib/react-native/ParseHooks.js @@ -0,0 +1,125 @@ +import CoreManager from './CoreManager'; +import decode from './decode'; +import encode from './encode'; +import ParseError from './ParseError'; +import ParsePromise from './ParsePromise'; + +export function getFunctions() { + return CoreManager.getHooksController().get("functions"); +} + +export function getTriggers() { + return CoreManager.getHooksController().get("triggers"); +} + +export function getFunction(name) { + return CoreManager.getHooksController().get("functions", name); +} + +export function getTrigger(className, triggerName) { + return CoreManager.getHooksController().get("triggers", className, triggerName); +} + +export function createFunction(functionName, url) { + return create({ functionName: functionName, url: url }); +} + +export function createTrigger(className, triggerName, url) { + return create({ className: className, triggerName: triggerName, url: url }); +} + +export function create(hook) { + return CoreManager.getHooksController().create(hook); +} + +export function updateFunction(functionName, url) { + return update({ functionName: functionName, url: url }); +} + +export function updateTrigger(className, triggerName, url) { + return update({ className: className, triggerName: triggerName, url: url }); +} + +export function update(hook) { + return CoreManager.getHooksController().update(hook); +} + +export function removeFunction(functionName) { + return remove({ functionName: functionName }); +} + +export function removeTrigger(className, triggerName) { + return remove({ className: className, triggerName: triggerName }); +} + +export function remove(hook) { + return CoreManager.getHooksController().remove(hook); +} + +var DefaultController = { + + get(type, functionName, triggerName) { + var url = "/hooks/" + type; + if (functionName) { + url += "/" + functionName; + if (triggerName) { + url += "/" + triggerName; + } + } + return this.sendRequest("GET", url); + }, + + create(hook) { + var url; + if (hook.functionName && hook.url) { + url = "/hooks/functions"; + } else if (hook.className && hook.triggerName && hook.url) { + url = "/hooks/triggers"; + } else { + return Promise.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest("POST", url, hook); + }, + + remove(hook) { + var url; + if (hook.functionName) { + url = "/hooks/functions/" + hook.functionName; + delete hook.functionName; + } else if (hook.className && hook.triggerName) { + url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; + delete hook.className; + delete hook.triggerName; + } else { + return Promise.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest("PUT", url, { "__op": "Delete" }); + }, + + update(hook) { + var url; + if (hook.functionName && hook.url) { + url = "/hooks/functions/" + hook.functionName; + delete hook.functionName; + } else if (hook.className && hook.triggerName && hook.url) { + url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; + delete hook.className; + delete hook.triggerName; + } else { + return Promise.reject({ error: 'invalid hook declaration', code: 143 }); + } + return this.sendRequest('PUT', url, hook); + }, + + sendRequest(method, url, body) { + return CoreManager.getRESTController().request(method, url, body, { useMasterKey: true }).then(res => { + var decoded = decode(res); + if (decoded) { + return ParsePromise.as(decoded); + } + return ParsePromise.error(new ParseError(ParseError.INVALID_JSON, 'The server returned an invalid response.')); + }); + } +}; + +CoreManager.setHooksController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseInstallation.js b/lib/react-native/ParseInstallation.js new file mode 100644 index 000000000..fd29a3f91 --- /dev/null +++ b/lib/react-native/ParseInstallation.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseObject from './ParseObject'; + +export default class Installation extends ParseObject { + constructor(attributes) { + super('_Installation'); + if (attributes && typeof attributes === 'object') { + if (!this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + } +} + +ParseObject.registerSubclass('_Installation', Installation); \ No newline at end of file diff --git a/lib/react-native/ParseLiveQuery.js b/lib/react-native/ParseLiveQuery.js new file mode 100644 index 000000000..3ad072a72 --- /dev/null +++ b/lib/react-native/ParseLiveQuery.js @@ -0,0 +1,212 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import EventEmitter from './EventEmitter'; +import LiveQueryClient from './LiveQueryClient'; +import CoreManager from './CoreManager'; +import ParsePromise from './ParsePromise'; + +function open() { + const LiveQueryController = CoreManager.getLiveQueryController(); + LiveQueryController.open(); +} + +function close() { + const LiveQueryController = CoreManager.getLiveQueryController(); + LiveQueryController.close(); +} + +/** + * + * We expose three events to help you monitor the status of the WebSocket connection: + * + *

              Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

              + * Parse.LiveQuery.on('open', () => {
              + * 
              + * });

              + * + *

              Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. + * + *

              + * Parse.LiveQuery.on('close', () => {
              + * 
              + * });

              + * + *

              Error - When some network error or LiveQuery server error happens, you'll get this event. + * + *

              + * Parse.LiveQuery.on('error', (error) => {
              + * 
              + * });

              + * + * @class Parse.LiveQuery + * @static + * + */ +let LiveQuery = new EventEmitter(); + +/** + * After open is called, the LiveQuery will try to send a connect request + * to the LiveQuery server. + * + * @method open + */ +LiveQuery.open = open; + +/** + * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). + * This function will close the WebSocket connection to the LiveQuery server, + * cancel the auto reconnect, and unsubscribe all subscriptions based on it. + * If you call query.subscribe() after this, we'll create a new WebSocket + * connection to the LiveQuery server. + * + * @method close + */ + +LiveQuery.close = close; +// Register a default onError callback to make sure we do not crash on error +LiveQuery.on('error', () => {}); + +export default LiveQuery; + +function getSessionToken() { + const controller = CoreManager.getUserController(); + return controller.currentUserAsync().then(currentUser => { + return currentUser ? currentUser.getSessionToken() : undefined; + }); +} + +function getLiveQueryClient() { + return CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); +} + +let defaultLiveQueryClient; +const DefaultLiveQueryController = { + setDefaultLiveQueryClient(liveQueryClient) { + defaultLiveQueryClient = liveQueryClient; + }, + getDefaultLiveQueryClient() { + if (defaultLiveQueryClient) { + return ParsePromise.as(defaultLiveQueryClient); + } + + return getSessionToken().then(sessionToken => { + let liveQueryServerURL = CoreManager.get('LIVEQUERY_SERVER_URL'); + + if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { + throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); + } + + // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL + if (!liveQueryServerURL) { + const tempServerURL = CoreManager.get('SERVER_URL'); + let protocol = 'ws://'; + // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix + if (tempServerURL.indexOf('https') === 0) { + protocol = 'wss://'; + } + const host = tempServerURL.replace(/^https?:\/\//, ''); + liveQueryServerURL = protocol + host; + CoreManager.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); + } + + const applicationId = CoreManager.get('APPLICATION_ID'); + const javascriptKey = CoreManager.get('JAVASCRIPT_KEY'); + const masterKey = CoreManager.get('MASTER_KEY'); + // Get currentUser sessionToken if possible + defaultLiveQueryClient = new LiveQueryClient({ + applicationId, + serverURL: liveQueryServerURL, + javascriptKey, + masterKey, + sessionToken + }); + // Register a default onError callback to make sure we do not crash on error + // Cannot create these events on a nested way because of EventEmiiter from React Native + defaultLiveQueryClient.on('error', error => { + LiveQuery.emit('error', error); + }); + defaultLiveQueryClient.on('open', () => { + LiveQuery.emit('open'); + }); + defaultLiveQueryClient.on('close', () => { + LiveQuery.emit('close'); + }); + + return defaultLiveQueryClient; + }); + }, + open() { + getLiveQueryClient().then(liveQueryClient => { + this.resolve(liveQueryClient.open()); + }); + }, + close() { + getLiveQueryClient().then(liveQueryClient => { + this.resolve(liveQueryClient.close()); + }); + }, + subscribe(query) { + let subscriptionWrap = new EventEmitter(); + + getLiveQueryClient().then(liveQueryClient => { + if (liveQueryClient.shouldOpen()) { + liveQueryClient.open(); + } + let promiseSessionToken = getSessionToken(); + // new event emitter + return promiseSessionToken.then(sessionToken => { + + let subscription = liveQueryClient.subscribe(query, sessionToken); + // enter, leave create, etc + + subscriptionWrap.id = subscription.id; + subscriptionWrap.query = subscription.query; + subscriptionWrap.sessionToken = subscription.sessionToken; + subscriptionWrap.unsubscribe = subscription.unsubscribe; + // Cannot create these events on a nested way because of EventEmiiter from React Native + subscription.on('open', () => { + subscriptionWrap.emit('open'); + }); + subscription.on('create', object => { + subscriptionWrap.emit('create', object); + }); + subscription.on('update', object => { + subscriptionWrap.emit('update', object); + }); + subscription.on('enter', object => { + subscriptionWrap.emit('enter', object); + }); + subscription.on('leave', object => { + subscriptionWrap.emit('leave', object); + }); + subscription.on('delete', object => { + subscriptionWrap.emit('delete', object); + }); + + this.resolve(); + }); + }); + return subscriptionWrap; + }, + unsubscribe(subscription) { + getLiveQueryClient().then(liveQueryClient => { + this.resolve(liveQueryClient.unsubscribe(subscription)); + }); + }, + _clearCachedDefaultClient() { + defaultLiveQueryClient = null; + } +}; + +CoreManager.setLiveQueryController(DefaultLiveQueryController); \ No newline at end of file diff --git a/lib/react-native/ParseObject.js b/lib/react-native/ParseObject.js new file mode 100644 index 000000000..e92c14e18 --- /dev/null +++ b/lib/react-native/ParseObject.js @@ -0,0 +1,1742 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import canBeSerialized from './canBeSerialized'; +import decode from './decode'; +import encode from './encode'; +import equals from './equals'; +import escape from './escape'; +import ParseACL from './ParseACL'; +import parseDate from './parseDate'; +import ParseError from './ParseError'; +import ParseFile from './ParseFile'; +import { opFromJSON, Op, SetOp, UnsetOp, IncrementOp, AddOp, AddUniqueOp, RemoveOp, RelationOp } from './ParseOp'; +import ParsePromise from './ParsePromise'; +import ParseQuery from './ParseQuery'; +import ParseRelation from './ParseRelation'; +import * as SingleInstanceStateController from './SingleInstanceStateController'; +import unique from './unique'; +import * as UniqueInstanceStateController from './UniqueInstanceStateController'; +import unsavedChildren from './unsavedChildren'; + +// Mapping of class names to constructors, so we can populate objects from the +// server with appropriate subclasses of ParseObject +var classMap = {}; + +// Global counter for generating unique local Ids +var localCount = 0; +// Global counter for generating unique Ids for non-single-instance objects +var objectCount = 0; +// On web clients, objects are single-instance: any two objects with the same Id +// will have the same attributes. However, this may be dangerous default +// behavior in a server scenario +var singleInstance = !CoreManager.get('IS_NODE'); +if (singleInstance) { + CoreManager.setObjectStateController(SingleInstanceStateController); +} else { + CoreManager.setObjectStateController(UniqueInstanceStateController); +} + +function getServerUrlPath() { + var serverUrl = CoreManager.get('SERVER_URL'); + if (serverUrl[serverUrl.length - 1] !== '/') { + serverUrl += '/'; + } + var url = serverUrl.replace(/https?:\/\//, ''); + return url.substr(url.indexOf('/')); +} + +/** + * Creates a new model with defined attributes. + * + *

              You won't normally call this method directly. It is recommended that + * you use a subclass of Parse.Object instead, created by calling + * extend.

              + * + *

              However, if you don't want to use a subclass, or aren't sure which + * subclass is appropriate, you can use this form:

              + *     var object = new Parse.Object("ClassName");
              + * 
              + * That is basically equivalent to:
              + *     var MyClass = Parse.Object.extend("ClassName");
              + *     var object = new MyClass();
              + * 

              + * + * @class Parse.Object + * @constructor + * @param {String} className The class name for the object + * @param {Object} attributes The initial set of data to store in the object. + * @param {Object} options The options for this object instance. + */ +export default class ParseObject { + /** + * The ID of this object, unique within its class. + * @property id + * @type String + */ + constructor(className, attributes, options) { + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + var toSet = null; + this._objCount = objectCount++; + if (typeof className === 'string') { + this.className = className; + if (attributes && typeof attributes === 'object') { + toSet = attributes; + } + } else if (className && typeof className === 'object') { + this.className = className.className; + toSet = {}; + for (var attr in className) { + if (attr !== 'className') { + toSet[attr] = className[attr]; + } + } + if (attributes && typeof attributes === 'object') { + options = attributes; + } + } + if (toSet && !this.set(toSet, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + + /** Prototype getters / setters **/ + + get attributes() { + let stateController = CoreManager.getObjectStateController(); + return Object.freeze(stateController.estimateAttributes(this._getStateIdentifier())); + } + + /** + * The first time this object was saved on the server. + * @property createdAt + * @type Date + */ + get createdAt() { + return this._getServerData().createdAt; + } + + /** + * The last time this object was updated on the server. + * @property updatedAt + * @type Date + */ + get updatedAt() { + return this._getServerData().updatedAt; + } + + /** Private methods **/ + + /** + * Returns a local or server Id used uniquely identify this object + */ + _getId() { + if (typeof this.id === 'string') { + return this.id; + } + if (typeof this._localId === 'string') { + return this._localId; + } + var localId = 'local' + String(localCount++); + this._localId = localId; + return localId; + } + + /** + * Returns a unique identifier used to pull data from the State Controller. + */ + _getStateIdentifier() { + if (singleInstance) { + let id = this.id; + if (!id) { + id = this._getId(); + } + return { + id: id, + className: this.className + }; + } else { + return this; + } + } + + _getServerData() { + let stateController = CoreManager.getObjectStateController(); + return stateController.getServerData(this._getStateIdentifier()); + } + + _clearServerData() { + var serverData = this._getServerData(); + var unset = {}; + for (var attr in serverData) { + unset[attr] = undefined; + } + let stateController = CoreManager.getObjectStateController(); + stateController.setServerData(this._getStateIdentifier(), unset); + } + + _getPendingOps() { + let stateController = CoreManager.getObjectStateController(); + return stateController.getPendingOps(this._getStateIdentifier()); + } + + _clearPendingOps() { + var pending = this._getPendingOps(); + var latest = pending[pending.length - 1]; + var keys = Object.keys(latest); + keys.forEach(key => { + delete latest[key]; + }); + } + + _getDirtyObjectAttributes() { + var attributes = this.attributes; + var stateController = CoreManager.getObjectStateController(); + var objectCache = stateController.getObjectCache(this._getStateIdentifier()); + var dirty = {}; + for (var attr in attributes) { + var val = attributes[attr]; + if (val && typeof val === 'object' && !(val instanceof ParseObject) && !(val instanceof ParseFile) && !(val instanceof ParseRelation)) { + // Due to the way browsers construct maps, the key order will not change + // unless the object is changed + try { + var json = encode(val, false, true); + var stringified = JSON.stringify(json); + if (objectCache[attr] !== stringified) { + dirty[attr] = val; + } + } catch (e) { + // Error occurred, possibly by a nested unsaved pointer in a mutable container + // No matter how it happened, it indicates a change in the attribute + dirty[attr] = val; + } + } + } + return dirty; + } + + _toFullJSON(seen) { + var json = this.toJSON(seen); + json.__type = 'Object'; + json.className = this.className; + return json; + } + + _getSaveJSON() { + var pending = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + var json = {}; + + for (var attr in dirtyObjects) { + json[attr] = new SetOp(dirtyObjects[attr]).toJSON(); + } + for (attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + return json; + } + + _getSaveParams() { + var method = this.id ? 'PUT' : 'POST'; + var body = this._getSaveJSON(); + var path = 'classes/' + this.className; + if (this.id) { + path += '/' + this.id; + } else if (this.className === '_User') { + path = 'users'; + } + return { + method, + body, + path + }; + } + + _finishFetch(serverData) { + if (!this.id && serverData.objectId) { + this.id = serverData.objectId; + } + let stateController = CoreManager.getObjectStateController(); + stateController.initializeState(this._getStateIdentifier()); + var decoded = {}; + for (var attr in serverData) { + if (attr === 'ACL') { + decoded[attr] = new ParseACL(serverData[attr]); + } else if (attr !== 'objectId') { + decoded[attr] = decode(serverData[attr]); + if (decoded[attr] instanceof ParseRelation) { + decoded[attr]._ensureParentAndKey(this, attr); + } + } + } + if (decoded.createdAt && typeof decoded.createdAt === 'string') { + decoded.createdAt = parseDate(decoded.createdAt); + } + if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { + decoded.updatedAt = parseDate(decoded.updatedAt); + } + if (!decoded.updatedAt && decoded.createdAt) { + decoded.updatedAt = decoded.createdAt; + } + stateController.commitServerChanges(this._getStateIdentifier(), decoded); + } + + _setExisted(existed) { + let stateController = CoreManager.getObjectStateController(); + let state = stateController.getState(this._getStateIdentifier()); + if (state) { + state.existed = existed; + } + } + + _migrateId(serverId) { + if (this._localId && serverId) { + if (singleInstance) { + let stateController = CoreManager.getObjectStateController(); + let oldState = stateController.removeState(this._getStateIdentifier()); + this.id = serverId; + delete this._localId; + if (oldState) { + stateController.initializeState(this._getStateIdentifier(), oldState); + } + } else { + this.id = serverId; + delete this._localId; + } + } + } + + _handleSaveResponse(response, status) { + var changes = {}; + + var stateController = CoreManager.getObjectStateController(); + var pending = stateController.popPendingState(this._getStateIdentifier()); + for (var attr in pending) { + if (pending[attr] instanceof RelationOp) { + changes[attr] = pending[attr].applyTo(undefined, this, attr); + } else if (!(attr in response)) { + // Only SetOps and UnsetOps should not come back with results + changes[attr] = pending[attr].applyTo(undefined); + } + } + for (attr in response) { + if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { + changes[attr] = parseDate(response[attr]); + } else if (attr === 'ACL') { + changes[attr] = new ParseACL(response[attr]); + } else if (attr !== 'objectId') { + changes[attr] = decode(response[attr]); + if (changes[attr] instanceof UnsetOp) { + changes[attr] = undefined; + } + } + } + if (changes.createdAt && !changes.updatedAt) { + changes.updatedAt = changes.createdAt; + } + + this._migrateId(response.objectId); + + if (status !== 201) { + this._setExisted(true); + } + + stateController.commitServerChanges(this._getStateIdentifier(), changes); + } + + _handleSaveError() { + this._getPendingOps(); + + let stateController = CoreManager.getObjectStateController(); + stateController.mergeFirstPendingState(this._getStateIdentifier()); + } + + /** Public methods **/ + + initialize() {} + // NOOP + + + /** + * Returns a JSON version of the object suitable for saving to Parse. + * @method toJSON + * @return {Object} + */ + toJSON(seen) { + var seenEntry = this.id ? this.className + ':' + this.id : this; + var seen = seen || [seenEntry]; + var json = {}; + var attrs = this.attributes; + for (var attr in attrs) { + if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { + json[attr] = attrs[attr].toJSON(); + } else { + json[attr] = encode(attrs[attr], false, false, seen); + } + } + var pending = this._getPendingOps(); + for (var attr in pending[0]) { + json[attr] = pending[0][attr].toJSON(); + } + + if (this.id) { + json.objectId = this.id; + } + return json; + } + + /** + * Determines whether this ParseObject is equal to another ParseObject + * @method equals + * @return {Boolean} + */ + equals(other) { + if (this === other) { + return true; + } + return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; + } + + /** + * Returns true if this object has been modified since its last + * save/refresh. If an attribute is specified, it returns true only if that + * particular attribute has been modified since the last save/refresh. + * @method dirty + * @param {String} attr An attribute name (optional). + * @return {Boolean} + */ + dirty(attr) { + if (!this.id) { + return true; + } + var pendingOps = this._getPendingOps(); + var dirtyObjects = this._getDirtyObjectAttributes(); + if (attr) { + if (dirtyObjects.hasOwnProperty(attr)) { + return true; + } + for (var i = 0; i < pendingOps.length; i++) { + if (pendingOps[i].hasOwnProperty(attr)) { + return true; + } + } + return false; + } + if (Object.keys(pendingOps[0]).length !== 0) { + return true; + } + if (Object.keys(dirtyObjects).length !== 0) { + return true; + } + return false; + } + + /** + * Returns an array of keys that have been modified since last save/refresh + * @method dirtyKeys + * @return {Array of string} + */ + dirtyKeys() { + var pendingOps = this._getPendingOps(); + var keys = {}; + for (var i = 0; i < pendingOps.length; i++) { + for (var attr in pendingOps[i]) { + keys[attr] = true; + } + } + var dirtyObjects = this._getDirtyObjectAttributes(); + for (var attr in dirtyObjects) { + keys[attr] = true; + } + return Object.keys(keys); + } + + /** + * Gets a Pointer referencing this Object. + * @method toPointer + * @return {Object} + */ + toPointer() { + if (!this.id) { + throw new Error('Cannot create a pointer to an unsaved ParseObject'); + } + return { + __type: 'Pointer', + className: this.className, + objectId: this.id + }; + } + + /** + * Gets the value of an attribute. + * @method get + * @param {String} attr The string name of an attribute. + */ + get(attr) { + return this.attributes[attr]; + } + + /** + * Gets a relation on the given class for the attribute. + * @method relation + * @param String attr The attribute to get the relation for. + */ + relation(attr) { + var value = this.get(attr); + if (value) { + if (!(value instanceof ParseRelation)) { + throw new Error('Called relation() on non-relation field ' + attr); + } + value._ensureParentAndKey(this, attr); + return value; + } + return new ParseRelation(this, attr); + } + + /** + * Gets the HTML-escaped value of an attribute. + * @method escape + * @param {String} attr The string name of an attribute. + */ + escape(attr) { + var val = this.attributes[attr]; + if (val == null) { + return ''; + } + + if (typeof val !== 'string') { + if (typeof val.toString !== 'function') { + return ''; + } + val = val.toString(); + } + return escape(val); + } + + /** + * Returns true if the attribute contains a value that is not + * null or undefined. + * @method has + * @param {String} attr The string name of the attribute. + * @return {Boolean} + */ + has(attr) { + var attributes = this.attributes; + if (attributes.hasOwnProperty(attr)) { + return attributes[attr] != null; + } + return false; + } + + /** + * Sets a hash of model attributes on the object. + * + *

              You can call it with an object containing keys and values, or with one + * key and value. For example:

              +   *   gameTurn.set({
              +   *     player: player1,
              +   *     diceRoll: 2
              +   *   }, {
              +   *     error: function(gameTurnAgain, error) {
              +   *       // The set failed validation.
              +   *     }
              +   *   });
              +   *
              +   *   game.set("currentPlayer", player2, {
              +   *     error: function(gameTurnAgain, error) {
              +   *       // The set failed validation.
              +   *     }
              +   *   });
              +   *
              +   *   game.set("finished", true);

              + * + * @method set + * @param {String} key The key to set. + * @param {} value The value to give it. + * @param {Object} options A set of options for the set. + * The only supported option is error. + * @return {Boolean} true if the set succeeded. + */ + set(key, value, options) { + var changes = {}; + var newOps = {}; + if (key && typeof key === 'object') { + changes = key; + options = value; + } else if (typeof key === 'string') { + changes[key] = value; + } else { + return this; + } + + options = options || {}; + var readonly = []; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var k in changes) { + if (k === 'createdAt' || k === 'updatedAt') { + // This property is read-only, but for legacy reasons we silently + // ignore it + continue; + } + if (readonly.indexOf(k) > -1) { + throw new Error('Cannot modify readonly attribute: ' + k); + } + if (options.unset) { + newOps[k] = new UnsetOp(); + } else if (changes[k] instanceof Op) { + newOps[k] = changes[k]; + } else if (changes[k] && typeof changes[k] === 'object' && typeof changes[k].__op === 'string') { + newOps[k] = opFromJSON(changes[k]); + } else if (k === 'objectId' || k === 'id') { + if (typeof changes[k] === 'string') { + this.id = changes[k]; + } + } else if (k === 'ACL' && typeof changes[k] === 'object' && !(changes[k] instanceof ParseACL)) { + newOps[k] = new SetOp(new ParseACL(changes[k])); + } else { + newOps[k] = new SetOp(changes[k]); + } + } + + // Calculate new values + var currentAttributes = this.attributes; + var newValues = {}; + for (var attr in newOps) { + if (newOps[attr] instanceof RelationOp) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); + } else if (!(newOps[attr] instanceof UnsetOp)) { + newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); + } + } + + // Validate changes + if (!options.ignoreValidation) { + var validation = this.validate(newValues); + if (validation) { + if (typeof options.error === 'function') { + options.error(this, validation); + } + return false; + } + } + + // Consolidate Ops + var pendingOps = this._getPendingOps(); + var last = pendingOps.length - 1; + var stateController = CoreManager.getObjectStateController(); + for (var attr in newOps) { + var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); + stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); + } + + return this; + } + + /** + * Remove an attribute from the model. This is a noop if the attribute doesn't + * exist. + * @method unset + * @param {String} attr The string name of an attribute. + */ + unset(attr, options) { + options = options || {}; + options.unset = true; + return this.set(attr, null, options); + } + + /** + * Atomically increments the value of the given attribute the next time the + * object is saved. If no amount is specified, 1 is used by default. + * + * @method increment + * @param attr {String} The key. + * @param amount {Number} The amount to increment by (optional). + */ + increment(attr, amount) { + if (typeof amount === 'undefined') { + amount = 1; + } + if (typeof amount !== 'number') { + throw new Error('Cannot increment by a non-numeric amount.'); + } + return this.set(attr, new IncrementOp(amount)); + } + + /** + * Atomically add an object to the end of the array associated with a given + * key. + * @method add + * @param attr {String} The key. + * @param item {} The item to add. + */ + add(attr, item) { + return this.set(attr, new AddOp([item])); + } + + /** + * Atomically add an object to the array associated with a given key, only + * if it is not already present in the array. The position of the insert is + * not guaranteed. + * + * @method addUnique + * @param attr {String} The key. + * @param item {} The object to add. + */ + addUnique(attr, item) { + return this.set(attr, new AddUniqueOp([item])); + } + + /** + * Atomically remove all instances of an object from the array associated + * with a given key. + * + * @method remove + * @param attr {String} The key. + * @param item {} The object to remove. + */ + remove(attr, item) { + return this.set(attr, new RemoveOp([item])); + } + + /** + * Returns an instance of a subclass of Parse.Op describing what kind of + * modification has been performed on this field since the last time it was + * saved. For example, after calling object.increment("x"), calling + * object.op("x") would return an instance of Parse.Op.Increment. + * + * @method op + * @param attr {String} The key. + * @returns {Parse.Op} The operation, or undefined if none. + */ + op(attr) { + var pending = this._getPendingOps(); + for (var i = pending.length; i--;) { + if (pending[i][attr]) { + return pending[i][attr]; + } + } + } + + /** + * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() + * @method clone + * @return {Parse.Object} + */ + clone() { + let clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + let attributes = this.attributes; + if (typeof this.constructor.readOnlyAttributes === 'function') { + let readonly = this.constructor.readOnlyAttributes() || []; + // Attributes are frozen, so we have to rebuild an object, + // rather than delete readonly keys + let copy = {}; + for (let a in attributes) { + if (readonly.indexOf(a) < 0) { + copy[a] = attributes[a]; + } + } + attributes = copy; + } + if (clone.set) { + clone.set(attributes); + } + return clone; + } + + /** + * Creates a new instance of this object. Not to be confused with clone() + * @method newInstance + * @return {Parse.Object} + */ + newInstance() { + let clone = new this.constructor(); + if (!clone.className) { + clone.className = this.className; + } + clone.id = this.id; + if (singleInstance) { + // Just return an object with the right id + return clone; + } + + let stateController = CoreManager.getObjectStateController(); + if (stateController) { + stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); + } + return clone; + } + + /** + * Returns true if this object has never been saved to Parse. + * @method isNew + * @return {Boolean} + */ + isNew() { + return !this.id; + } + + /** + * Returns true if this object was created by the Parse server when the + * object might have already been there (e.g. in the case of a Facebook + * login) + * @method existed + * @return {Boolean} + */ + existed() { + if (!this.id) { + return false; + } + let stateController = CoreManager.getObjectStateController(); + let state = stateController.getState(this._getStateIdentifier()); + if (state) { + return state.existed; + } + return false; + } + + /** + * Checks if the model is currently in a valid state. + * @method isValid + * @return {Boolean} + */ + isValid() { + return !this.validate(this.attributes); + } + + /** + * You should not call this function directly unless you subclass + * Parse.Object, in which case you can override this method + * to provide additional validation on set and + * save. Your implementation should return + * + * @method validate + * @param {Object} attrs The current data to validate. + * @return {} False if the data is valid. An error object otherwise. + * @see Parse.Object#set + */ + validate(attrs) { + if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof ParseACL)) { + return new ParseError(ParseError.OTHER_CAUSE, 'ACL must be a Parse ACL.'); + } + for (var key in attrs) { + if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { + return new ParseError(ParseError.INVALID_KEY_NAME); + } + } + return false; + } + + /** + * Returns the ACL for this object. + * @method getACL + * @returns {Parse.ACL} An instance of Parse.ACL. + * @see Parse.Object#get + */ + getACL() { + var acl = this.get('ACL'); + if (acl instanceof ParseACL) { + return acl; + } + return null; + } + + /** + * Sets the ACL to be used for this object. + * @method setACL + * @param {Parse.ACL} acl An instance of Parse.ACL. + * @param {Object} options Optional Backbone-like options object to be + * passed in to set. + * @return {Boolean} Whether the set passed validation. + * @see Parse.Object#set + */ + setACL(acl, options) { + return this.set('ACL', acl, options); + } + + /** + * Clears any changes to this object made since the last call to save() + * @method revert + */ + revert() { + this._clearPendingOps(); + } + + /** + * Clears all attributes on a model + * @method clear + */ + clear() { + var attributes = this.attributes; + var erasable = {}; + var readonly = ['createdAt', 'updatedAt']; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); + } + for (var attr in attributes) { + if (readonly.indexOf(attr) < 0) { + erasable[attr] = true; + } + } + return this.set(erasable, { unset: true }); + } + + /** + * Fetch the model from the server. If the server's representation of the + * model differs from its current attributes, they will be overriden. + * + * @method fetch + * @param {Object} options A Backbone-style callback object. + * Valid options are:
                + *
              • success: A Backbone-style success callback. + *
              • error: An Backbone-style error callback. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * @return {Parse.Promise} A promise that is fulfilled when the fetch + * completes. + */ + fetch(options) { + options = options || {}; + var fetchOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + fetchOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + fetchOptions.sessionToken = options.sessionToken; + } + var controller = CoreManager.getObjectController(); + return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); + } + + /** + * Set a hash of model attributes, and save the model to the server. + * updatedAt will be updated when the request returns. + * You can either call it as:
              +   *   object.save();
              + * or
              +   *   object.save(null, options);
              + * or
              +   *   object.save(attrs, options);
              + * or
              +   *   object.save(key, value, options);
              + * + * For example,
              +   *   gameTurn.save({
              +   *     player: "Jake Cutter",
              +   *     diceRoll: 2
              +   *   }, {
              +   *     success: function(gameTurnAgain) {
              +   *       // The save was successful.
              +   *     },
              +   *     error: function(gameTurnAgain, error) {
              +   *       // The save failed.  Error is an instance of Parse.Error.
              +   *     }
              +   *   });
              + * or with promises:
              +   *   gameTurn.save({
              +   *     player: "Jake Cutter",
              +   *     diceRoll: 2
              +   *   }).then(function(gameTurnAgain) {
              +   *     // The save was successful.
              +   *   }, function(error) {
              +   *     // The save failed.  Error is an instance of Parse.Error.
              +   *   });
              + * + * @method save + * @param {Object} options A Backbone-style callback object. + * Valid options are:
                + *
              • success: A Backbone-style success callback. + *
              • error: An Backbone-style error callback. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * @return {Parse.Promise} A promise that is fulfilled when the save + * completes. + */ + save(arg1, arg2, arg3) { + var attrs; + var options; + if (typeof arg1 === 'object' || typeof arg1 === 'undefined') { + attrs = arg1; + if (typeof arg2 === 'object') { + options = arg2; + } + } else { + attrs = {}; + attrs[arg1] = arg2; + options = arg3; + } + + // Support save({ success: function() {}, error: function() {} }) + if (!options && attrs) { + options = {}; + if (typeof attrs.success === 'function') { + options.success = attrs.success; + delete attrs.success; + } + if (typeof attrs.error === 'function') { + options.error = attrs.error; + delete attrs.error; + } + } + + if (attrs) { + var validation = this.validate(attrs); + if (validation) { + if (options && typeof options.error === 'function') { + options.error(this, validation); + } + return ParsePromise.error(validation); + } + this.set(attrs, options); + } + + options = options || {}; + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = !!options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { + saveOptions.sessionToken = options.sessionToken; + } + + var controller = CoreManager.getObjectController(); + var unsaved = unsavedChildren(this); + return controller.save(unsaved, saveOptions).then(() => { + return controller.save(this, saveOptions); + })._thenRunCallbacks(options, this); + } + + /** + * Destroy this model on the server if it was already persisted. + * If `wait: true` is passed, waits for the server to respond + * before removal. + * + * @method destroy + * @param {Object} options A Backbone-style callback object. + * Valid options are:
                + *
              • success: A Backbone-style success callback + *
              • error: An Backbone-style error callback. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * @return {Parse.Promise} A promise that is fulfilled when the destroy + * completes. + */ + destroy(options) { + options = options || {}; + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + if (!this.id) { + return ParsePromise.as()._thenRunCallbacks(options); + } + return CoreManager.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); + } + + /** Static methods **/ + + static _clearAllState() { + let stateController = CoreManager.getObjectStateController(); + stateController.clearAllState(); + } + + /** + * Fetches the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
              +   *   Parse.Object.fetchAll([object1, object2, ...], {
              +   *     success: function(list) {
              +   *       // All the objects were fetched.
              +   *     },
              +   *     error: function(error) {
              +   *       // An error occurred while fetching one of the objects.
              +   *     },
              +   *   });
              +   * 
              + * + * @method fetchAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
                + *
              • success: A Backbone-style success callback. + *
              • error: An Backbone-style error callback. + *
              + */ + static fetchAll(list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return CoreManager.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); + } + + /** + * Fetches the given list of Parse.Object if needed. + * If any error is encountered, stops and calls the error handler. + * + *
              +   *   Parse.Object.fetchAllIfNeeded([object1, ...], {
              +   *     success: function(list) {
              +   *       // Objects were fetched and updated.
              +   *     },
              +   *     error: function(error) {
              +   *       // An error occurred while fetching one of the objects.
              +   *     },
              +   *   });
              +   * 
              + * + * @method fetchAllIfNeeded + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
                + *
              • success: A Backbone-style success callback. + *
              • error: An Backbone-style error callback. + *
              + */ + static fetchAllIfNeeded(list, options) { + var options = options || {}; + + var queryOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + queryOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + queryOptions.sessionToken = options.sessionToken; + } + return CoreManager.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); + } + + /** + * Destroy the given list of models on the server if it was already persisted. + * + *

              Unlike saveAll, if an error occurs while deleting an individual model, + * this method will continue trying to delete the rest of the models if + * possible, except in the case of a fatal error like a connection error. + * + *

              In particular, the Parse.Error object returned in the case of error may + * be one of two types: + * + *

                + *
              • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an + * array of other Parse.Error objects. Each error object in this array + * has an "object" property that references the object that could not be + * deleted (for instance, because that object could not be found).
              • + *
              • A non-aggregate Parse.Error. This indicates a serious error that + * caused the delete operation to be aborted partway through (for + * instance, a connection failure in the middle of the delete).
              • + *
              + * + *
              +   *   Parse.Object.destroyAll([object1, object2, ...], {
              +   *     success: function() {
              +   *       // All the objects were deleted.
              +   *     },
              +   *     error: function(error) {
              +   *       // An error occurred while deleting one or more of the objects.
              +   *       // If this is an aggregate error, then we can inspect each error
              +   *       // object individually to determine the reason why a particular
              +   *       // object was not deleted.
              +   *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
              +   *         for (var i = 0; i < error.errors.length; i++) {
              +   *           console.log("Couldn't delete " + error.errors[i].object.id +
              +   *             "due to " + error.errors[i].message);
              +   *         }
              +   *       } else {
              +   *         console.log("Delete aborted because of " + error.message);
              +   *       }
              +   *     },
              +   *   });
              +   * 
              + * + * @method destroyAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
                + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * @return {Parse.Promise} A promise that is fulfilled when the destroyAll + * completes. + */ + static destroyAll(list, options) { + var options = options || {}; + + var destroyOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + destroyOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + destroyOptions.sessionToken = options.sessionToken; + } + return CoreManager.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); + } + + /** + * Saves the given list of Parse.Object. + * If any error is encountered, stops and calls the error handler. + * + *
              +   *   Parse.Object.saveAll([object1, object2, ...], {
              +   *     success: function(list) {
              +   *       // All the objects were saved.
              +   *     },
              +   *     error: function(error) {
              +   *       // An error occurred while saving one of the objects.
              +   *     },
              +   *   });
              +   * 
              + * + * @method saveAll + * @param {Array} list A list of Parse.Object. + * @param {Object} options A Backbone-style callback object. + * @static + * Valid options are:
                + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + */ + static saveAll(list, options) { + var options = options || {}; + + var saveOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + saveOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + saveOptions.sessionToken = options.sessionToken; + } + return CoreManager.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); + } + + /** + * Creates a reference to a subclass of Parse.Object with the given id. This + * does not exist on Parse.Object, only on subclasses. + * + *

              A shortcut for:

              +   *  var Foo = Parse.Object.extend("Foo");
              +   *  var pointerToFoo = new Foo();
              +   *  pointerToFoo.id = "myObjectId";
              +   * 
              + * + * @method createWithoutData + * @param {String} id The ID of the object to create a reference to. + * @static + * @return {Parse.Object} A Parse.Object reference. + */ + static createWithoutData(id) { + var obj = new this(); + obj.id = id; + return obj; + } + + /** + * Creates a new instance of a Parse Object from a JSON representation. + * @method fromJSON + * @param {Object} json The JSON map of the Object's data + * @param {boolean} override In single instance mode, all old server data + * is overwritten if this is set to true + * @static + * @return {Parse.Object} A Parse.Object reference + */ + static fromJSON(json, override) { + if (!json.className) { + throw new Error('Cannot create an object without a className'); + } + var constructor = classMap[json.className]; + var o = constructor ? new constructor() : new ParseObject(json.className); + var otherAttributes = {}; + for (var attr in json) { + if (attr !== 'className' && attr !== '__type') { + otherAttributes[attr] = json[attr]; + } + } + if (override) { + // id needs to be set before clearServerData can work + if (otherAttributes.objectId) { + o.id = otherAttributes.objectId; + } + let preserved = null; + if (typeof o._preserveFieldsOnFetch === 'function') { + preserved = o._preserveFieldsOnFetch(); + } + o._clearServerData(); + if (preserved) { + o._finishFetch(preserved); + } + } + o._finishFetch(otherAttributes); + if (json.objectId) { + o._setExisted(true); + } + return o; + } + + /** + * Registers a subclass of Parse.Object with a specific class name. + * When objects of that class are retrieved from a query, they will be + * instantiated with this subclass. + * This is only necessary when using ES6 subclassing. + * @method registerSubclass + * @param {String} className The class name of the subclass + * @param {Class} constructor The subclass + */ + static registerSubclass(className, constructor) { + if (typeof className !== 'string') { + throw new TypeError('The first argument must be a valid class name.'); + } + if (typeof constructor === 'undefined') { + throw new TypeError('You must supply a subclass constructor.'); + } + if (typeof constructor !== 'function') { + throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); + } + classMap[className] = constructor; + if (!constructor.className) { + constructor.className = className; + } + } + + /** + * Creates a new subclass of Parse.Object for the given Parse class name. + * + *

              Every extension of a Parse class will inherit from the most recent + * previous extension of that class. When a Parse.Object is automatically + * created by parsing JSON, it will use the most recent extension of that + * class.

              + * + *

              You should call either:

              +   *     var MyClass = Parse.Object.extend("MyClass", {
              +   *         Instance methods,
              +   *         initialize: function(attrs, options) {
              +   *             this.someInstanceProperty = [],
              +   *             Other instance properties
              +   *         }
              +   *     }, {
              +   *         Class properties
              +   *     });
              + * or, for Backbone compatibility:
              +   *     var MyClass = Parse.Object.extend({
              +   *         className: "MyClass",
              +   *         Instance methods,
              +   *         initialize: function(attrs, options) {
              +   *             this.someInstanceProperty = [],
              +   *             Other instance properties
              +   *         }
              +   *     }, {
              +   *         Class properties
              +   *     });

              + * + * @method extend + * @param {String} className The name of the Parse class backing this model. + * @param {Object} protoProps Instance properties to add to instances of the + * class returned from this method. + * @param {Object} classProps Class properties to add the class returned from + * this method. + * @return {Class} A new subclass of Parse.Object. + */ + static extend(className, protoProps, classProps) { + if (typeof className !== 'string') { + if (className && typeof className.className === 'string') { + return ParseObject.extend(className.className, className, protoProps); + } else { + throw new Error('Parse.Object.extend\'s first argument should be the className.'); + } + } + var adjustedClassName = className; + + if (adjustedClassName === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) { + adjustedClassName = '_User'; + } + + var parentProto = ParseObject.prototype; + if (this.hasOwnProperty('__super__') && this.__super__) { + parentProto = this.prototype; + } else if (classMap[adjustedClassName]) { + parentProto = classMap[adjustedClassName].prototype; + } + var ParseObjectSubclass = function (attributes, options) { + this.className = adjustedClassName; + this._objCount = objectCount++; + // Enable legacy initializers + if (typeof this.initialize === 'function') { + this.initialize.apply(this, arguments); + } + + if (attributes && typeof attributes === 'object') { + if (!this.set(attributes || {}, options)) { + throw new Error('Can\'t create an invalid Parse Object'); + } + } + }; + ParseObjectSubclass.className = adjustedClassName; + ParseObjectSubclass.__super__ = parentProto; + + ParseObjectSubclass.prototype = Object.create(parentProto, { + constructor: { + value: ParseObjectSubclass, + enumerable: false, + writable: true, + configurable: true + } + }); + + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + Object.defineProperty(ParseObjectSubclass.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + Object.defineProperty(ParseObjectSubclass, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + ParseObjectSubclass.extend = function (name, protoProps, classProps) { + if (typeof name === 'string') { + return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); + } + return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); + }; + ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; + + classMap[adjustedClassName] = ParseObjectSubclass; + return ParseObjectSubclass; + } + + /** + * Enable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * This is disabled by default in server environments, since it can lead to + * security issues. + * @method enableSingleInstance + */ + static enableSingleInstance() { + singleInstance = true; + CoreManager.setObjectStateController(SingleInstanceStateController); + } + + /** + * Disable single instance objects, where any local objects with the same Id + * share the same attributes, and stay synchronized with each other. + * When disabled, you can have two instances of the same object in memory + * without them sharing attributes. + * @method disableSingleInstance + */ + static disableSingleInstance() { + singleInstance = false; + CoreManager.setObjectStateController(UniqueInstanceStateController); + } +} + +var DefaultController = { + fetch(target, forceFetch, options) { + if (Array.isArray(target)) { + if (target.length < 1) { + return ParsePromise.as([]); + } + var objs = []; + var ids = []; + var className = null; + var results = []; + var error = null; + target.forEach((el, i) => { + if (error) { + return; + } + if (!className) { + className = el.className; + } + if (className !== el.className) { + error = new ParseError(ParseError.INVALID_CLASS_NAME, 'All objects should be of the same class'); + } + if (!el.id) { + error = new ParseError(ParseError.MISSING_OBJECT_ID, 'All objects must have an ID'); + } + if (forceFetch || Object.keys(el._getServerData()).length === 0) { + ids.push(el.id); + objs.push(el); + } + results.push(el); + }); + if (error) { + return ParsePromise.error(error); + } + var query = new ParseQuery(className); + query.containedIn('objectId', ids); + query._limit = ids.length; + return query.find(options).then(objects => { + var idMap = {}; + objects.forEach(o => { + idMap[o.id] = o; + }); + for (var i = 0; i < objs.length; i++) { + var obj = objs[i]; + if (!obj || !obj.id || !idMap[obj.id]) { + if (forceFetch) { + return ParsePromise.error(new ParseError(ParseError.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); + } + } + } + if (!singleInstance) { + // If single instance objects are disabled, we need to replace the + for (var i = 0; i < results.length; i++) { + var obj = results[i]; + if (obj && obj.id && idMap[obj.id]) { + var id = obj.id; + obj._finishFetch(idMap[id].toJSON()); + results[i] = idMap[id]; + } + } + } + return ParsePromise.as(results); + }); + } else { + var RESTController = CoreManager.getRESTController(); + return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then((response, status, xhr) => { + if (target instanceof ParseObject) { + target._clearPendingOps(); + target._clearServerData(); + target._finishFetch(response); + } + return target; + }); + } + }, + + destroy(target, options) { + var RESTController = CoreManager.getRESTController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return ParsePromise.as([]); + } + var batches = [[]]; + target.forEach(obj => { + if (!obj.id) { + return; + } + batches[batches.length - 1].push(obj); + if (batches[batches.length - 1].length >= 20) { + batches.push([]); + } + }); + if (batches[batches.length - 1].length === 0) { + // If the last batch is empty, remove it + batches.pop(); + } + var deleteCompleted = ParsePromise.as(); + var errors = []; + batches.forEach(batch => { + deleteCompleted = deleteCompleted.then(() => { + return RESTController.request('POST', 'batch', { + requests: batch.map(obj => { + return { + method: 'DELETE', + path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), + body: {} + }; + }) + }, options).then(results => { + for (var i = 0; i < results.length; i++) { + if (results[i] && results[i].hasOwnProperty('error')) { + var err = new ParseError(results[i].error.code, results[i].error.error); + err.object = batch[i]; + errors.push(err); + } + } + }); + }); + }); + return deleteCompleted.then(() => { + if (errors.length) { + var aggregate = new ParseError(ParseError.AGGREGATE_ERROR); + aggregate.errors = errors; + return ParsePromise.error(aggregate); + } + return ParsePromise.as(target); + }); + } else if (target instanceof ParseObject) { + return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(() => { + return ParsePromise.as(target); + }); + } + return ParsePromise.as(target); + }, + + save(target, options) { + var RESTController = CoreManager.getRESTController(); + var stateController = CoreManager.getObjectStateController(); + if (Array.isArray(target)) { + if (target.length < 1) { + return ParsePromise.as([]); + } + + var unsaved = target.concat(); + for (var i = 0; i < target.length; i++) { + if (target[i] instanceof ParseObject) { + unsaved = unsaved.concat(unsavedChildren(target[i], true)); + } + } + unsaved = unique(unsaved); + + var filesSaved = ParsePromise.as(); + var pending = []; + unsaved.forEach(el => { + if (el instanceof ParseFile) { + filesSaved = filesSaved.then(() => { + return el.save(); + }); + } else if (el instanceof ParseObject) { + pending.push(el); + } + }); + + return filesSaved.then(() => { + var objectError = null; + return ParsePromise._continueWhile(() => { + return pending.length > 0; + }, () => { + var batch = []; + var nextPending = []; + pending.forEach(el => { + if (batch.length < 20 && canBeSerialized(el)) { + batch.push(el); + } else { + nextPending.push(el); + } + }); + pending = nextPending; + if (batch.length < 1) { + return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); + } + + // Queue up tasks for each object in the batch. + // When every task is ready, the API request will execute + var batchReturned = new ParsePromise(); + var batchReady = []; + var batchTasks = []; + batch.forEach((obj, index) => { + var ready = new ParsePromise(); + batchReady.push(ready); + + stateController.pushPendingState(obj._getStateIdentifier()); + batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { + ready.resolve(); + return batchReturned.then((responses, status) => { + if (responses[index].hasOwnProperty('success')) { + obj._handleSaveResponse(responses[index].success, status); + } else { + if (!objectError && responses[index].hasOwnProperty('error')) { + var serverError = responses[index].error; + objectError = new ParseError(serverError.code, serverError.error); + // Cancel the rest of the save + pending = []; + } + obj._handleSaveError(); + } + }); + })); + }); + + ParsePromise.when(batchReady).then(() => { + // Kick off the batch request + return RESTController.request('POST', 'batch', { + requests: batch.map(obj => { + var params = obj._getSaveParams(); + params.path = getServerUrlPath() + params.path; + return params; + }) + }, options); + }).then((response, status, xhr) => { + batchReturned.resolve(response, status); + }); + + return ParsePromise.when(batchTasks); + }).then(() => { + if (objectError) { + return ParsePromise.error(objectError); + } + return ParsePromise.as(target); + }); + }); + } else if (target instanceof ParseObject) { + // copying target lets Flow guarantee the pointer isn't modified elsewhere + var targetCopy = target; + var task = function () { + var params = targetCopy._getSaveParams(); + return RESTController.request(params.method, params.path, params.body, options).then((response, status) => { + targetCopy._handleSaveResponse(response, status); + }, error => { + targetCopy._handleSaveError(); + return ParsePromise.error(error); + }); + }; + + stateController.pushPendingState(target._getStateIdentifier()); + return stateController.enqueueTask(target._getStateIdentifier(), task).then(() => { + return target; + }, error => { + return ParsePromise.error(error); + }); + } + return ParsePromise.as(); + } +}; + +CoreManager.setObjectController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseOp.js b/lib/react-native/ParseOp.js new file mode 100644 index 000000000..db70be82c --- /dev/null +++ b/lib/react-native/ParseOp.js @@ -0,0 +1,434 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import arrayContainsObject from './arrayContainsObject'; +import decode from './decode'; +import encode from './encode'; +import ParseObject from './ParseObject'; +import ParseRelation from './ParseRelation'; +import unique from './unique'; + +export function opFromJSON(json) { + if (!json || !json.__op) { + return null; + } + switch (json.__op) { + case 'Delete': + return new UnsetOp(); + case 'Increment': + return new IncrementOp(json.amount); + case 'Add': + return new AddOp(decode(json.objects)); + case 'AddUnique': + return new AddUniqueOp(decode(json.objects)); + case 'Remove': + return new RemoveOp(decode(json.objects)); + case 'AddRelation': + var toAdd = decode(json.objects); + if (!Array.isArray(toAdd)) { + return new RelationOp([], []); + } + return new RelationOp(toAdd, []); + case 'RemoveRelation': + var toRemove = decode(json.objects); + if (!Array.isArray(toRemove)) { + return new RelationOp([], []); + } + return new RelationOp([], toRemove); + case 'Batch': + var toAdd = []; + var toRemove = []; + for (var i = 0; i < json.ops.length; i++) { + if (json.ops[i].__op === 'AddRelation') { + toAdd = toAdd.concat(decode(json.ops[i].objects)); + } else if (json.ops[i].__op === 'RemoveRelation') { + toRemove = toRemove.concat(decode(json.ops[i].objects)); + } + } + return new RelationOp(toAdd, toRemove); + } + return null; +} + +export class Op { + // Empty parent class + applyTo(value) {} + mergeWith(previous) {} + toJSON() {} +} + +export class SetOp extends Op { + + constructor(value) { + super(); + this._value = value; + } + + applyTo(value) { + return this._value; + } + + mergeWith(previous) { + return new SetOp(this._value); + } + + toJSON() { + return encode(this._value, false, true); + } +} + +export class UnsetOp extends Op { + applyTo(value) { + return undefined; + } + + mergeWith(previous) { + return new UnsetOp(); + } + + toJSON() { + return { __op: 'Delete' }; + } +} + +export class IncrementOp extends Op { + + constructor(amount) { + super(); + if (typeof amount !== 'number') { + throw new TypeError('Increment Op must be initialized with a numeric amount.'); + } + this._amount = amount; + } + + applyTo(value) { + if (typeof value === 'undefined') { + return this._amount; + } + if (typeof value !== 'number') { + throw new TypeError('Cannot increment a non-numeric value.'); + } + return this._amount + value; + } + + mergeWith(previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._amount); + } + if (previous instanceof IncrementOp) { + return new IncrementOp(this.applyTo(previous._amount)); + } + throw new Error('Cannot merge Increment Op with the previous Op'); + } + + toJSON() { + return { __op: 'Increment', amount: this._amount }; + } +} + +export class AddOp extends Op { + + constructor(value) { + super(); + this._value = Array.isArray(value) ? value : [value]; + } + + applyTo(value) { + if (value == null) { + return this._value; + } + if (Array.isArray(value)) { + return value.concat(this._value); + } + throw new Error('Cannot add elements to a non-array value'); + } + + mergeWith(previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddOp) { + return new AddOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge Add Op with the previous Op'); + } + + toJSON() { + return { __op: 'Add', objects: encode(this._value, false, true) }; + } +} + +export class AddUniqueOp extends Op { + + constructor(value) { + super(); + this._value = unique(Array.isArray(value) ? value : [value]); + } + + applyTo(value) { + if (value == null) { + return this._value || []; + } + if (Array.isArray(value)) { + // copying value lets Flow guarantee the pointer isn't modified elsewhere + var valueCopy = value; + var toAdd = []; + this._value.forEach(v => { + if (v instanceof ParseObject) { + if (!arrayContainsObject(valueCopy, v)) { + toAdd.push(v); + } + } else { + if (valueCopy.indexOf(v) < 0) { + toAdd.push(v); + } + } + }); + return value.concat(toAdd); + } + throw new Error('Cannot add elements to a non-array value'); + } + + mergeWith(previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new SetOp(this._value); + } + if (previous instanceof AddUniqueOp) { + return new AddUniqueOp(this.applyTo(previous._value)); + } + throw new Error('Cannot merge AddUnique Op with the previous Op'); + } + + toJSON() { + return { __op: 'AddUnique', objects: encode(this._value, false, true) }; + } +} + +export class RemoveOp extends Op { + + constructor(value) { + super(); + this._value = unique(Array.isArray(value) ? value : [value]); + } + + applyTo(value) { + if (value == null) { + return []; + } + if (Array.isArray(value)) { + var i = value.indexOf(this._value); + var removed = value.concat([]); + for (var i = 0; i < this._value.length; i++) { + var index = removed.indexOf(this._value[i]); + while (index > -1) { + removed.splice(index, 1); + index = removed.indexOf(this._value[i]); + } + if (this._value[i] instanceof ParseObject && this._value[i].id) { + for (var j = 0; j < removed.length; j++) { + if (removed[j] instanceof ParseObject && this._value[i].id === removed[j].id) { + removed.splice(j, 1); + j--; + } + } + } + } + return removed; + } + throw new Error('Cannot remove elements from a non-array value'); + } + + mergeWith(previous) { + if (!previous) { + return this; + } + if (previous instanceof SetOp) { + return new SetOp(this.applyTo(previous._value)); + } + if (previous instanceof UnsetOp) { + return new UnsetOp(); + } + if (previous instanceof RemoveOp) { + var uniques = previous._value.concat([]); + for (var i = 0; i < this._value.length; i++) { + if (this._value[i] instanceof ParseObject) { + if (!arrayContainsObject(uniques, this._value[i])) { + uniques.push(this._value[i]); + } + } else { + if (uniques.indexOf(this._value[i]) < 0) { + uniques.push(this._value[i]); + } + } + } + return new RemoveOp(uniques); + } + throw new Error('Cannot merge Remove Op with the previous Op'); + } + + toJSON() { + return { __op: 'Remove', objects: encode(this._value, false, true) }; + } +} + +export class RelationOp extends Op { + + constructor(adds, removes) { + super(); + this._targetClassName = null; + + if (Array.isArray(adds)) { + this.relationsToAdd = unique(adds.map(this._extractId, this)); + } + + if (Array.isArray(removes)) { + this.relationsToRemove = unique(removes.map(this._extractId, this)); + } + } + + _extractId(obj) { + if (typeof obj === 'string') { + return obj; + } + if (!obj.id) { + throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); + } + if (!this._targetClassName) { + this._targetClassName = obj.className; + } + if (this._targetClassName !== obj.className) { + throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); + } + return obj.id; + } + + applyTo(value, object, key) { + if (!value) { + if (!object || !key) { + throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); + } + var parent = new ParseObject(object.className); + if (object.id && object.id.indexOf('local') === 0) { + parent._localId = object.id; + } else if (object.id) { + parent.id = object.id; + } + var relation = new ParseRelation(parent, key); + relation.targetClassName = this._targetClassName; + return relation; + } + if (value instanceof ParseRelation) { + if (this._targetClassName) { + if (value.targetClassName) { + if (this._targetClassName !== value.targetClassName) { + throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); + } + } else { + value.targetClassName = this._targetClassName; + } + } + return value; + } else { + throw new Error('Relation cannot be applied to a non-relation field'); + } + } + + mergeWith(previous) { + if (!previous) { + return this; + } else if (previous instanceof UnsetOp) { + throw new Error('You cannot modify a relation after deleting it.'); + } else if (previous instanceof RelationOp) { + if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { + throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); + } + var newAdd = previous.relationsToAdd.concat([]); + this.relationsToRemove.forEach(r => { + var index = newAdd.indexOf(r); + if (index > -1) { + newAdd.splice(index, 1); + } + }); + this.relationsToAdd.forEach(r => { + var index = newAdd.indexOf(r); + if (index < 0) { + newAdd.push(r); + } + }); + + var newRemove = previous.relationsToRemove.concat([]); + this.relationsToAdd.forEach(r => { + var index = newRemove.indexOf(r); + if (index > -1) { + newRemove.splice(index, 1); + } + }); + this.relationsToRemove.forEach(r => { + var index = newRemove.indexOf(r); + if (index < 0) { + newRemove.push(r); + } + }); + + var newRelation = new RelationOp(newAdd, newRemove); + newRelation._targetClassName = this._targetClassName; + return newRelation; + } + throw new Error('Cannot merge Relation Op with the previous Op'); + } + + toJSON() { + var idToPointer = id => { + return { + __type: 'Pointer', + className: this._targetClassName, + objectId: id + }; + }; + + var adds = null; + var removes = null; + var pointers = null; + + if (this.relationsToAdd.length > 0) { + pointers = this.relationsToAdd.map(idToPointer); + adds = { __op: 'AddRelation', objects: pointers }; + } + if (this.relationsToRemove.length > 0) { + pointers = this.relationsToRemove.map(idToPointer); + removes = { __op: 'RemoveRelation', objects: pointers }; + } + + if (adds && removes) { + return { __op: 'Batch', ops: [adds, removes] }; + } + + return adds || removes || {}; + } +} \ No newline at end of file diff --git a/lib/react-native/ParsePromise.js b/lib/react-native/ParsePromise.js new file mode 100644 index 000000000..ef7626b6d --- /dev/null +++ b/lib/react-native/ParsePromise.js @@ -0,0 +1,575 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +var isPromisesAPlusCompliant = true; + +/** + * A Promise is returned by async methods as a hook to provide callbacks to be + * called when the async task is fulfilled. + * + *

              Typical usage would be like:

              + *    query.find().then(function(results) {
              + *      results[0].set("foo", "bar");
              + *      return results[0].saveAsync();
              + *    }).then(function(result) {
              + *      console.log("Updated " + result.id);
              + *    });
              + * 

              + * + * @class Parse.Promise + * @constructor + */ +export default class ParsePromise { + constructor(executor) { + this._resolved = false; + this._rejected = false; + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + + if (typeof executor === 'function') { + executor(this.resolve.bind(this), this.reject.bind(this)); + } + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method resolve + * @param {Object} result the result to pass to the callbacks. + */ + resolve(...results) { + if (this._resolved || this._rejected) { + throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._resolved = true; + this._result = results; + for (var i = 0; i < this._resolvedCallbacks.length; i++) { + this._resolvedCallbacks[i].apply(this, results); + } + + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Marks this promise as fulfilled, firing any callbacks waiting on it. + * @method reject + * @param {Object} error the error to pass to the callbacks. + */ + reject(error) { + if (this._resolved || this._rejected) { + throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); + } + this._rejected = true; + this._error = error; + for (var i = 0; i < this._rejectedCallbacks.length; i++) { + this._rejectedCallbacks[i](error); + } + this._resolvedCallbacks = []; + this._rejectedCallbacks = []; + } + + /** + * Adds callbacks to be called when this promise is fulfilled. Returns a new + * Promise that will be fulfilled when the callback is complete. It allows + * chaining. If the callback itself returns a Promise, then the one returned + * by "then" will not be fulfilled until that one returned by the callback + * is fulfilled. + * @method then + * @param {Function} resolvedCallback Function that is called when this + * Promise is resolved. Once the callback is complete, then the Promise + * returned by "then" will also be fulfilled. + * @param {Function} rejectedCallback Function that is called when this + * Promise is rejected with an error. Once the callback is complete, then + * the promise returned by "then" with be resolved successfully. If + * rejectedCallback is null, or it returns a rejected Promise, then the + * Promise returned by "then" will be rejected with that error. + * @return {Parse.Promise} A new Promise that will be fulfilled after this + * Promise is fulfilled and either callback has completed. If the callback + * returned a Promise, then this Promise will not be fulfilled until that + * one is. + */ + then(resolvedCallback, rejectedCallback) { + var promise = new ParsePromise(); + + var wrappedResolvedCallback = function (...results) { + if (typeof resolvedCallback === 'function') { + if (isPromisesAPlusCompliant) { + try { + results = [resolvedCallback.apply(this, results)]; + } catch (e) { + results = [ParsePromise.error(e)]; + } + } else { + results = [resolvedCallback.apply(this, results)]; + } + } + if (results.length === 1 && ParsePromise.is(results[0])) { + results[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + promise.resolve.apply(promise, results); + } + }; + + var wrappedRejectedCallback = function (error) { + var result = []; + if (typeof rejectedCallback === 'function') { + if (isPromisesAPlusCompliant) { + try { + result = [rejectedCallback(error)]; + } catch (e) { + result = [ParsePromise.error(e)]; + } + } else { + result = [rejectedCallback(error)]; + } + if (result.length === 1 && ParsePromise.is(result[0])) { + result[0].then(function () { + promise.resolve.apply(promise, arguments); + }, function (error) { + promise.reject(error); + }); + } else { + if (isPromisesAPlusCompliant) { + promise.resolve.apply(promise, result); + } else { + promise.reject(result[0]); + } + } + } else { + promise.reject(error); + } + }; + + var runLater = function (fn) { + fn.call(); + }; + if (isPromisesAPlusCompliant) { + if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { + runLater = function (fn) { + process.nextTick(fn); + }; + } else if (typeof setTimeout === 'function') { + runLater = function (fn) { + setTimeout(fn, 0); + }; + } + } + + if (this._resolved) { + runLater(() => { + wrappedResolvedCallback.apply(this, this._result); + }); + } else if (this._rejected) { + runLater(() => { + wrappedRejectedCallback(this._error); + }); + } else { + this._resolvedCallbacks.push(wrappedResolvedCallback); + this._rejectedCallbacks.push(wrappedRejectedCallback); + } + + return promise; + } + + /** + * Add handlers to be called when the promise + * is either resolved or rejected + * @method always + */ + always(callback) { + return this.then(callback, callback); + } + + /** + * Add handlers to be called when the Promise object is resolved + * @method done + */ + done(callback) { + return this.then(callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * Alias for catch(). + * @method fail + */ + fail(callback) { + return this.then(null, callback); + } + + /** + * Add handlers to be called when the Promise object is rejected + * @method catch + */ + catch(callback) { + return this.then(null, callback); + } + + /** + * Run the given callbacks after this promise is fulfilled. + * @method _thenRunCallbacks + * @param optionsOrCallback {} A Backbone-style options callback, or a + * callback function. If this is an options object and contains a "model" + * attributes, that will be passed to error callbacks as the first argument. + * @param model {} If truthy, this will be passed as the first result of + * error callbacks. This is for Backbone-compatability. + * @return {Parse.Promise} A promise that will be resolved after the + * callbacks are run, with the same result as this. + */ + _thenRunCallbacks(optionsOrCallback, model) { + var options = {}; + if (typeof optionsOrCallback === 'function') { + options.success = function (result) { + optionsOrCallback(result, null); + }; + options.error = function (error) { + optionsOrCallback(null, error); + }; + } else if (typeof optionsOrCallback === 'object') { + if (typeof optionsOrCallback.success === 'function') { + options.success = optionsOrCallback.success; + } + if (typeof optionsOrCallback.error === 'function') { + options.error = optionsOrCallback.error; + } + } + + return this.then(function (...results) { + if (options.success) { + options.success.apply(this, results); + } + return ParsePromise.as.apply(ParsePromise, arguments); + }, function (error) { + if (options.error) { + if (typeof model !== 'undefined') { + options.error(model, error); + } else { + options.error(error); + } + } + // By explicitly returning a rejected Promise, this will work with + // either jQuery or Promises/A+ semantics. + return ParsePromise.error(error); + }); + } + + /** + * Adds a callback function that should be called regardless of whether + * this promise failed or succeeded. The callback will be given either the + * array of results for its first argument, or the error as its second, + * depending on whether this Promise was rejected or resolved. Returns a + * new Promise, like "then" would. + * @method _continueWith + * @param {Function} continuation the callback. + */ + _continueWith(continuation) { + return this.then(function (...args) { + return continuation(args, null); + }, function (error) { + return continuation(null, error); + }); + } + + /** + * Returns true iff the given object fulfils the Promise interface. + * @method is + * @param {Object} promise The object to test + * @static + * @return {Boolean} + */ + static is(promise) { + return promise != null && typeof promise.then === 'function'; + } + + /** + * Returns a new promise that is resolved with a given value. + * @method as + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + static as(...values) { + var promise = new ParsePromise(); + promise.resolve.apply(promise, values); + return promise; + } + + /** + * Returns a new promise that is resolved with a given value. + * If that value is a thenable Promise (has a .then() prototype + * method), the new promise will be chained to the end of the + * value. + * @method resolve + * @param value The value to resolve the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + static resolve(value) { + return new ParsePromise((resolve, reject) => { + if (ParsePromise.is(value)) { + value.then(resolve, reject); + } else { + resolve(value); + } + }); + } + + /** + * Returns a new promise that is rejected with a given error. + * @method error + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + static error(...errors) { + var promise = new ParsePromise(); + promise.reject.apply(promise, errors); + return promise; + } + + /** + * Returns a new promise that is rejected with a given error. + * This is an alias for Parse.Promise.error, for compliance with + * the ES6 implementation. + * @method reject + * @param error The error to reject the promise with + * @static + * @return {Parse.Promise} the new promise. + */ + static reject(...errors) { + return ParsePromise.error.apply(null, errors); + } + + /** + * Returns a new promise that is fulfilled when all of the input promises + * are resolved. If any promise in the list fails, then the returned promise + * will be rejected with an array containing the error from each promise. + * If they all succeed, then the returned promise will succeed, with the + * results being the results of all the input + * promises. For example:
              +   *   var p1 = Parse.Promise.as(1);
              +   *   var p2 = Parse.Promise.as(2);
              +   *   var p3 = Parse.Promise.as(3);
              +   *
              +   *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
              +   *     console.log(r1);  // prints 1
              +   *     console.log(r2);  // prints 2
              +   *     console.log(r3);  // prints 3
              +   *   });
              + * + * The input promises can also be specified as an array:
              +   *   var promises = [p1, p2, p3];
              +   *   Parse.Promise.when(promises).then(function(results) {
              +   *     console.log(results);  // prints [1,2,3]
              +   *   });
              +   * 
              + * @method when + * @param {Array} promises a list of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + static when(promises) { + var objects; + var arrayArgument = Array.isArray(promises); + if (arrayArgument) { + objects = promises; + } else { + objects = arguments; + } + + var total = objects.length; + var hadError = false; + var results = []; + var returnValue = arrayArgument ? [results] : results; + var errors = []; + results.length = objects.length; + errors.length = objects.length; + + if (total === 0) { + return ParsePromise.as.apply(this, returnValue); + } + + var promise = new ParsePromise(); + + var resolveOne = function () { + total--; + if (total <= 0) { + if (hadError) { + promise.reject(errors); + } else { + promise.resolve.apply(promise, returnValue); + } + } + }; + + var chain = function (object, index) { + if (ParsePromise.is(object)) { + object.then(function (result) { + results[index] = result; + resolveOne(); + }, function (error) { + errors[index] = error; + hadError = true; + resolveOne(); + }); + } else { + results[i] = object; + resolveOne(); + } + }; + for (var i = 0; i < objects.length; i++) { + chain(objects[i], i); + } + + return promise; + } + + /** + * Returns a new promise that is fulfilled when all of the promises in the + * iterable argument are resolved. If any promise in the list fails, then + * the returned promise will be immediately rejected with the reason that + * single promise rejected. If they all succeed, then the returned promise + * will succeed, with the results being the results of all the input + * promises. If the iterable provided is empty, the returned promise will + * be immediately resolved. + * + * For example:
              +   *   var p1 = Parse.Promise.as(1);
              +   *   var p2 = Parse.Promise.as(2);
              +   *   var p3 = Parse.Promise.as(3);
              +   *
              +   *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
              +   *     console.log(r1);  // prints 1
              +   *     console.log(r2);  // prints 2
              +   *     console.log(r3);  // prints 3
              +   *   });
              + * + * @method all + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + static all(promises) { + let total = 0; + let objects = []; + + for (let p of promises) { + objects[total++] = p; + } + + if (total === 0) { + return ParsePromise.as([]); + } + + let hadError = false; + let promise = new ParsePromise(); + let resolved = 0; + let results = []; + objects.forEach((object, i) => { + if (ParsePromise.is(object)) { + object.then(result => { + if (hadError) { + return false; + } + results[i] = result; + resolved++; + if (resolved >= total) { + promise.resolve(results); + } + }, error => { + // Reject immediately + promise.reject(error); + hadError = true; + }); + } else { + results[i] = object; + resolved++; + if (!hadError && resolved >= total) { + promise.resolve(results); + } + } + }); + + return promise; + } + + /** + * Returns a new promise that is immediately fulfilled when any of the + * promises in the iterable argument are resolved or rejected. If the + * first promise to complete is resolved, the returned promise will be + * resolved with the same value. Likewise, if the first promise to + * complete is rejected, the returned promise will be rejected with the + * same reason. + * + * @method race + * @param {Iterable} promises an iterable of promises to wait for. + * @static + * @return {Parse.Promise} the new promise. + */ + static race(promises) { + let completed = false; + let promise = new ParsePromise(); + for (let p of promises) { + if (ParsePromise.is(p)) { + p.then(result => { + if (completed) { + return; + } + completed = true; + promise.resolve(result); + }, error => { + if (completed) { + return; + } + completed = true; + promise.reject(error); + }); + } else if (!completed) { + completed = true; + promise.resolve(p); + } + } + + return promise; + } + + /** + * Runs the given asyncFunction repeatedly, as long as the predicate + * function returns a truthy value. Stops repeating if asyncFunction returns + * a rejected promise. + * @method _continueWhile + * @param {Function} predicate should return false when ready to stop. + * @param {Function} asyncFunction should return a Promise. + * @static + */ + static _continueWhile(predicate, asyncFunction) { + if (predicate()) { + return asyncFunction().then(function () { + return ParsePromise._continueWhile(predicate, asyncFunction); + }); + } + return ParsePromise.as(); + } + + static isPromisesAPlusCompliant() { + return isPromisesAPlusCompliant; + } + + static enableAPlusCompliant() { + isPromisesAPlusCompliant = true; + } + + static disableAPlusCompliant() { + isPromisesAPlusCompliant = false; + } +} \ No newline at end of file diff --git a/lib/react-native/ParseQuery.js b/lib/react-native/ParseQuery.js new file mode 100644 index 000000000..a32275dc1 --- /dev/null +++ b/lib/react-native/ParseQuery.js @@ -0,0 +1,1113 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import encode from './encode'; +import ParseError from './ParseError'; +import ParseGeoPoint from './ParseGeoPoint'; +import ParseObject from './ParseObject'; +import ParsePromise from './ParsePromise'; + +/** + * Converts a string into a regex that matches it. + * Surrounding with \Q .. \E does this, we just need to escape any \E's in + * the text separately. + */ +function quote(s) { + return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; +} + +/** + * Handles pre-populating the result data of a query with select fields, + * making sure that the data object contains keys for all objects that have + * been requested with a select, so that our cached state updates correctly. + */ +function handleSelectResult(data, select) { + var serverDataMask = {}; + + select.forEach(field => { + let hasSubObjectSelect = field.indexOf(".") !== -1; + if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { + // this field was selected, but is missing from the retrieved data + data[field] = undefined; + } else if (hasSubObjectSelect) { + // this field references a sub-object, + // so we need to walk down the path components + let pathComponents = field.split("."); + var obj = data; + var serverMask = serverDataMask; + + pathComponents.forEach((component, index, arr) => { + // add keys if the expected data is missing + if (!obj[component]) { + obj[component] = index == arr.length - 1 ? undefined : {}; + } + obj = obj[component]; + + //add this path component to the server mask so we can fill it in later if needed + if (index < arr.length - 1) { + if (!serverMask[component]) { + serverMask[component] = {}; + } + } + }); + } + }); + + if (Object.keys(serverDataMask).length > 0) { + // When selecting from sub-objects, we don't want to blow away the missing + // information that we may have retrieved before. We've already added any + // missing selected keys to sub-objects, but we still need to add in the + // data for any previously retrieved sub-objects that were not selected. + + let serverData = CoreManager.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); + + function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { + //copy missing elements at this level + if (copyThisLevel) { + for (var key in src) { + if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { + dest[key] = src[key]; + } + } + } + for (var key in mask) { + //traverse into objects as needed + copyMissingDataWithMask(src[key], dest[key], mask[key], true); + } + } + + copyMissingDataWithMask(serverData, data, serverDataMask, false); + } +} + +/** + * Creates a new parse Parse.Query for the given Parse.Object subclass. + * @class Parse.Query + * @constructor + * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. + * + *

              Parse.Query defines a query that is used to fetch Parse.Objects. The + * most common use case is finding all objects that match a query through the + * find method. For example, this sample code fetches all objects + * of class MyClass. It calls a different function depending on + * whether the fetch succeeded or not. + * + *

              + * var query = new Parse.Query(MyClass);
              + * query.find({
              + *   success: function(results) {
              + *     // results is an array of Parse.Object.
              + *   },
              + *
              + *   error: function(error) {
              + *     // error is an instance of Parse.Error.
              + *   }
              + * });

              + * + *

              A Parse.Query can also be used to retrieve a single object whose id is + * known, through the get method. For example, this sample code fetches an + * object of class MyClass and id myId. It calls a + * different function depending on whether the fetch succeeded or not. + * + *

              + * var query = new Parse.Query(MyClass);
              + * query.get(myId, {
              + *   success: function(object) {
              + *     // object is an instance of Parse.Object.
              + *   },
              + *
              + *   error: function(object, error) {
              + *     // error is an instance of Parse.Error.
              + *   }
              + * });

              + * + *

              A Parse.Query can also be used to count the number of objects that match + * the query without retrieving all of those objects. For example, this + * sample code counts the number of objects of the class MyClass + *

              + * var query = new Parse.Query(MyClass);
              + * query.count({
              + *   success: function(number) {
              + *     // There are number instances of MyClass.
              + *   },
              + *
              + *   error: function(error) {
              + *     // error is an instance of Parse.Error.
              + *   }
              + * });

              + */ +export default class ParseQuery { + + constructor(objectClass) { + if (typeof objectClass === 'string') { + if (objectClass === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) { + this.className = '_User'; + } else { + this.className = objectClass; + } + } else if (objectClass instanceof ParseObject) { + this.className = objectClass.className; + } else if (typeof objectClass === 'function') { + if (typeof objectClass.className === 'string') { + this.className = objectClass.className; + } else { + var obj = new objectClass(); + this.className = obj.className; + } + } else { + throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); + } + + this._where = {}; + this._include = []; + this._limit = -1; // negative limit is not sent in the server request + this._skip = 0; + this._extraOptions = {}; + } + + /** + * Adds constraint that at least one of the passed in queries matches. + * @method _orQuery + * @param {Array} queries + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + _orQuery(queries) { + var queryJSON = queries.map(q => { + return q.toJSON().where; + }); + + this._where.$or = queryJSON; + return this; + } + + /** + * Helper for condition queries + */ + _addCondition(key, condition, value) { + if (!this._where[key] || typeof this._where[key] === 'string') { + this._where[key] = {}; + } + this._where[key][condition] = encode(value, false, true); + return this; + } + + /** + * Converts string for regular expression at the beginning + */ + _regexStartWith(string) { + return '^' + quote(string); + } + + /** + * Returns a JSON representation of this query. + * @method toJSON + * @return {Object} The JSON representation of the query. + */ + toJSON() { + var params = { + where: this._where + }; + + if (this._include.length) { + params.include = this._include.join(','); + } + if (this._select) { + params.keys = this._select.join(','); + } + if (this._limit >= 0) { + params.limit = this._limit; + } + if (this._skip > 0) { + params.skip = this._skip; + } + if (this._order) { + params.order = this._order.join(','); + } + for (var key in this._extraOptions) { + params[key] = this._extraOptions[key]; + } + + return params; + } + + /** + * Constructs a Parse.Object whose id is already known by fetching data from + * the server. Either options.success or options.error is called when the + * find completes. + * + * @method get + * @param {String} objectId The id of the object to be fetched. + * @param {Object} options A Backbone-style options object. + * Valid options are:
                + *
              • success: A Backbone-style success callback + *
              • error: An Backbone-style error callback. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * + * @return {Parse.Promise} A promise that is resolved with the result when + * the query completes. + */ + get(objectId, options) { + this.equalTo('objectId', objectId); + + var firstOptions = {}; + if (options && options.hasOwnProperty('useMasterKey')) { + firstOptions.useMasterKey = options.useMasterKey; + } + if (options && options.hasOwnProperty('sessionToken')) { + firstOptions.sessionToken = options.sessionToken; + } + + return this.first(firstOptions).then(response => { + if (response) { + return response; + } + + var errorObject = new ParseError(ParseError.OBJECT_NOT_FOUND, 'Object not found.'); + return ParsePromise.error(errorObject); + })._thenRunCallbacks(options, null); + } + + /** + * Retrieves a list of ParseObjects that satisfy this query. + * Either options.success or options.error is called when the find + * completes. + * + * @method find + * @param {Object} options A Backbone-style options object. Valid options + * are:
                + *
              • success: Function to call when the find completes successfully. + *
              • error: Function to call when the find fails. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * + * @return {Parse.Promise} A promise that is resolved with the results when + * the query completes. + */ + find(options) { + options = options || {}; + + let findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + let controller = CoreManager.getQueryController(); + + let select = this._select; + + return controller.find(this.className, this.toJSON(), findOptions).then(response => { + return response.results.map(data => { + // In cases of relations, the server may send back a className + // on the top level of the payload + let override = response.className || this.className; + if (!data.className) { + data.className = override; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(data, select); + } + + return ParseObject.fromJSON(data, !select); + }); + })._thenRunCallbacks(options); + } + + /** + * Counts the number of objects that match this query. + * Either options.success or options.error is called when the count + * completes. + * + * @method count + * @param {Object} options A Backbone-style options object. Valid options + * are:
                + *
              • success: Function to call when the count completes successfully. + *
              • error: Function to call when the find fails. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * + * @return {Parse.Promise} A promise that is resolved with the count when + * the query completes. + */ + count(options) { + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = CoreManager.getQueryController(); + + var params = this.toJSON(); + params.limit = 0; + params.count = 1; + + return controller.find(this.className, params, findOptions).then(result => { + return result.count; + })._thenRunCallbacks(options); + } + + /** + * Retrieves at most one Parse.Object that satisfies this query. + * + * Either options.success or options.error is called when it completes. + * success is passed the object if there is one. otherwise, undefined. + * + * @method first + * @param {Object} options A Backbone-style options object. Valid options + * are:
                + *
              • success: Function to call when the find completes successfully. + *
              • error: Function to call when the find fails. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * + * @return {Parse.Promise} A promise that is resolved with the object when + * the query completes. + */ + first(options) { + options = options || {}; + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var controller = CoreManager.getQueryController(); + + var params = this.toJSON(); + params.limit = 1; + + var select = this._select; + + return controller.find(this.className, params, findOptions).then(response => { + var objects = response.results; + if (!objects[0]) { + return undefined; + } + if (!objects[0].className) { + objects[0].className = this.className; + } + + // Make sure the data object contains keys for all objects that + // have been requested with a select, so that our cached state + // updates correctly. + if (select) { + handleSelectResult(objects[0], select); + } + + return ParseObject.fromJSON(objects[0], !select); + })._thenRunCallbacks(options); + } + + /** + * Iterates over each result of a query, calling a callback for each one. If + * the callback returns a promise, the iteration will not continue until + * that promise has been fulfilled. If the callback returns a rejected + * promise, then iteration will stop with that error. The items are + * processed in an unspecified order. The query may not have any sort order, + * and may not use limit or skip. + * @method each + * @param {Function} callback Callback that will be called with each result + * of the query. + * @param {Object} options A Backbone-style options object. Valid options + * are:
                + *
              • success: Function to call when the iteration completes successfully. + *
              • error: Function to call when the iteration fails. + *
              • useMasterKey: In Cloud Code and Node only, causes the Master Key to + * be used for this request. + *
              • sessionToken: A valid session token, used for making a request on + * behalf of a specific user. + *
              + * @return {Parse.Promise} A promise that will be fulfilled once the + * iteration has completed. + */ + each(callback, options) { + options = options || {}; + + if (this._order || this._skip || this._limit >= 0) { + return ParsePromise.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); + } + + new ParsePromise(); + + + var query = new ParseQuery(this.className); + // We can override the batch size from the options. + // This is undocumented, but useful for testing. + query._limit = options.batchSize || 100; + query._include = this._include.map(i => { + return i; + }); + if (this._select) { + query._select = this._select.map(s => { + return s; + }); + } + + query._where = {}; + for (var attr in this._where) { + var val = this._where[attr]; + if (Array.isArray(val)) { + query._where[attr] = val.map(v => { + return v; + }); + } else if (val && typeof val === 'object') { + var conditionMap = {}; + query._where[attr] = conditionMap; + for (var cond in val) { + conditionMap[cond] = val[cond]; + } + } else { + query._where[attr] = val; + } + } + + query.ascending('objectId'); + + var findOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + findOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('sessionToken')) { + findOptions.sessionToken = options.sessionToken; + } + + var finished = false; + return ParsePromise._continueWhile(() => { + return !finished; + }, () => { + return query.find(findOptions).then(results => { + var callbacksDone = ParsePromise.as(); + results.forEach(result => { + callbacksDone = callbacksDone.then(() => { + return callback(result); + }); + }); + + return callbacksDone.then(() => { + if (results.length >= query._limit) { + query.greaterThan('objectId', results[results.length - 1].id); + } else { + finished = true; + } + }); + }); + })._thenRunCallbacks(options); + } + + /** Query Conditions **/ + + /** + * Adds a constraint to the query that requires a particular key's value to + * be equal to the provided value. + * @method equalTo + * @param {String} key The key to check. + * @param value The value that the Parse.Object must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + equalTo(key, value) { + if (typeof value === 'undefined') { + return this.doesNotExist(key); + } + + this._where[key] = encode(value, false, true); + return this; + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be not equal to the provided value. + * @method notEqualTo + * @param {String} key The key to check. + * @param value The value that must not be equalled. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + notEqualTo(key, value) { + return this._addCondition(key, '$ne', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than the provided value. + * @method lessThan + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + lessThan(key, value) { + return this._addCondition(key, '$lt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than the provided value. + * @method greaterThan + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + greaterThan(key, value) { + return this._addCondition(key, '$gt', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be less than or equal to the provided value. + * @method lessThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an upper bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + lessThanOrEqualTo(key, value) { + return this._addCondition(key, '$lte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be greater than or equal to the provided value. + * @method greaterThanOrEqualTo + * @param {String} key The key to check. + * @param value The value that provides an lower bound. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + greaterThanOrEqualTo(key, value) { + return this._addCondition(key, '$gte', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * be contained in the provided list of values. + * @method containedIn + * @param {String} key The key to check. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + containedIn(key, value) { + return this._addCondition(key, '$in', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * not be contained in the provided list of values. + * @method notContainedIn + * @param {String} key The key to check. + * @param {Array} values The values that will not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + notContainedIn(key, value) { + return this._addCondition(key, '$nin', value); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values. + * @method containsAll + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The values that will match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + containsAll(key, values) { + return this._addCondition(key, '$all', values); + } + + /** + * Adds a constraint to the query that requires a particular key's value to + * contain each one of the provided list of values starting with given strings. + * @method containsAllStartingWith + * @param {String} key The key to check. This key's value must be an array. + * @param {Array} values The string values that will match as starting string. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + containsAllStartingWith(key, values) { + var _this = this; + if (!Array.isArray(values)) { + values = [values]; + } + + values = values.map(function (value) { + return { "$regex": _this._regexStartWith(value) }; + }); + + return this.containsAll(key, values); + } + + /** + * Adds a constraint for finding objects that contain the given key. + * @method exists + * @param {String} key The key that should exist. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + exists(key) { + return this._addCondition(key, '$exists', true); + } + + /** + * Adds a constraint for finding objects that do not contain a given key. + * @method doesNotExist + * @param {String} key The key that should not exist + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + doesNotExist(key) { + return this._addCondition(key, '$exists', false); + } + + /** + * Adds a regular expression constraint for finding string values that match + * the provided regular expression. + * This may be slow for large datasets. + * @method matches + * @param {String} key The key that the string to match is stored in. + * @param {RegExp} regex The regular expression pattern to match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + matches(key, regex, modifiers) { + this._addCondition(key, '$regex', regex); + if (!modifiers) { + modifiers = ''; + } + if (regex.ignoreCase) { + modifiers += 'i'; + } + if (regex.multiline) { + modifiers += 'm'; + } + if (modifiers.length) { + this._addCondition(key, '$options', modifiers); + } + return this; + } + + /** + * Adds a constraint that requires that a key's value matches a Parse.Query + * constraint. + * @method matchesQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + matchesQuery(key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$inQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value not matches a + * Parse.Query constraint. + * @method doesNotMatchQuery + * @param {String} key The key that the contains the object to match the + * query. + * @param {Parse.Query} query The query that should not match. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + doesNotMatchQuery(key, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$notInQuery', queryJSON); + } + + /** + * Adds a constraint that requires that a key's value matches a value in + * an object returned by a different Parse.Query. + * @method matchesKeyInQuery + * @param {String} key The key that contains the value that is being + * matched. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + matchesKeyInQuery(key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$select', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint that requires that a key's value not match a value in + * an object returned by a different Parse.Query. + * @method doesNotMatchKeyInQuery + * @param {String} key The key that contains the value that is being + * excluded. + * @param {String} queryKey The key in the objects returned by the query to + * match against. + * @param {Parse.Query} query The query to run. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + doesNotMatchKeyInQuery(key, queryKey, query) { + var queryJSON = query.toJSON(); + queryJSON.className = query.className; + return this._addCondition(key, '$dontSelect', { + key: queryKey, + query: queryJSON + }); + } + + /** + * Adds a constraint for finding string values that contain a provided + * string. This may be slow for large datasets. + * @method contains + * @param {String} key The key that the string to match is stored in. + * @param {String} substring The substring that the value must contain. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + contains(key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value)); + } + + /** + * Adds a constraint for finding string values that start with a provided + * string. This query will use the backend index, so it will be fast even + * for large datasets. + * @method startsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} prefix The substring that the value must start with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + startsWith(key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', this._regexStartWith(value)); + } + + /** + * Adds a constraint for finding string values that end with a provided + * string. This will be slow for large datasets. + * @method endsWith + * @param {String} key The key that the string to match is stored in. + * @param {String} suffix The substring that the value must end with. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + endsWith(key, value) { + if (typeof value !== 'string') { + throw new Error('The value being searched for must be a string.'); + } + return this._addCondition(key, '$regex', quote(value) + '$'); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given. + * @method near + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + near(key, point) { + if (!(point instanceof ParseGeoPoint)) { + // Try to cast it as a GeoPoint + point = new ParseGeoPoint(point); + } + return this._addCondition(key, '$nearSphere', point); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * @method withinRadians + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in radians) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + withinRadians(key, point, distance) { + this.near(key, point); + return this._addCondition(key, '$maxDistance', distance); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 3958.8 miles. + * @method withinMiles + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in miles) of results to + * return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + withinMiles(key, point, distance) { + return this.withinRadians(key, point, distance / 3958.8); + } + + /** + * Adds a proximity based constraint for finding objects with key point + * values near the point given and within the maximum distance given. + * Radius of earth used is 6371.0 kilometers. + * @method withinKilometers + * @param {String} key The key that the Parse.GeoPoint is stored in. + * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. + * @param {Number} maxDistance Maximum distance (in kilometers) of results + * to return. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + withinKilometers(key, point, distance) { + return this.withinRadians(key, point, distance / 6371.0); + } + + /** + * Adds a constraint to the query that requires a particular key's + * coordinates be contained within a given rectangular geographic bounding + * box. + * @method withinGeoBox + * @param {String} key The key to be constrained. + * @param {Parse.GeoPoint} southwest + * The lower-left inclusive corner of the box. + * @param {Parse.GeoPoint} northeast + * The upper-right inclusive corner of the box. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + withinGeoBox(key, southwest, northeast) { + if (!(southwest instanceof ParseGeoPoint)) { + southwest = new ParseGeoPoint(southwest); + } + if (!(northeast instanceof ParseGeoPoint)) { + northeast = new ParseGeoPoint(northeast); + } + this._addCondition(key, '$within', { '$box': [southwest, northeast] }); + return this; + } + + /** Query Orderings **/ + + /** + * Sorts the results in ascending order by the given key. + * + * @method ascending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + ascending(...keys) { + this._order = []; + return this.addAscending.apply(this, keys); + } + + /** + * Sorts the results in ascending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addAscending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + addAscending(...keys) { + if (!this._order) { + this._order = []; + } + keys.forEach(key => { + if (Array.isArray(key)) { + key = key.join(); + } + this._order = this._order.concat(key.replace(/\s/g, '').split(',')); + }); + + return this; + } + + /** + * Sorts the results in descending order by the given key. + * + * @method descending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + descending(...keys) { + this._order = []; + return this.addDescending.apply(this, keys); + } + + /** + * Sorts the results in descending order by the given key, + * but can also add secondary sort descriptors without overwriting _order. + * + * @method addDescending + * @param {(String|String[]|...String} key The key to order by, which is a + * string of comma separated values, or an Array of keys, or multiple keys. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + addDescending(...keys) { + if (!this._order) { + this._order = []; + } + keys.forEach(key => { + if (Array.isArray(key)) { + key = key.join(); + } + this._order = this._order.concat(key.replace(/\s/g, '').split(',').map(k => { + return '-' + k; + })); + }); + + return this; + } + + /** Query Options **/ + + /** + * Sets the number of results to skip before returning any results. + * This is useful for pagination. + * Default is to skip zero results. + * @method skip + * @param {Number} n the number of results to skip. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + skip(n) { + if (typeof n !== 'number' || n < 0) { + throw new Error('You can only skip by a positive number'); + } + this._skip = n; + return this; + } + + /** + * Sets the limit of the number of results to return. The default limit is + * 100, with a maximum of 1000 results being returned at a time. + * @method limit + * @param {Number} n the number of results to limit to. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + limit(n) { + if (typeof n !== 'number') { + throw new Error('You can only set the limit to a numeric value'); + } + this._limit = n; + return this; + } + + /** + * Includes nested Parse.Objects for the provided key. You can use dot + * notation to specify which fields in the included object are also fetched. + * @method include + * @param {String} key The name of the key to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + include(...keys) { + keys.forEach(key => { + if (Array.isArray(key)) { + this._include = this._include.concat(key); + } else { + this._include.push(key); + } + }); + return this; + } + + /** + * Restricts the fields of the returned Parse.Objects to include only the + * provided keys. If this is called multiple times, then all of the keys + * specified in each of the calls will be included. + * @method select + * @param {Array} keys The names of the keys to include. + * @return {Parse.Query} Returns the query, so you can chain this call. + */ + select(...keys) { + if (!this._select) { + this._select = []; + } + keys.forEach(key => { + if (Array.isArray(key)) { + this._select = this._select.concat(key); + } else { + this._select.push(key); + } + }); + return this; + } + + /** + * Subscribe this query to get liveQuery updates + * @method subscribe + * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter + * which can be used to get liveQuery updates. + */ + subscribe() { + let controller = CoreManager.getLiveQueryController(); + return controller.subscribe(this); + } + + /** + * Constructs a Parse.Query that is the OR of the passed in queries. For + * example: + *
              var compoundQuery = Parse.Query.or(query1, query2, query3);
              + * + * will create a compoundQuery that is an or of the query1, query2, and + * query3. + * @method or + * @param {...Parse.Query} var_args The list of queries to OR. + * @static + * @return {Parse.Query} The query that is the OR of the passed in queries. + */ + static or(...queries) { + var className = null; + queries.forEach(q => { + if (!className) { + className = q.className; + } + + if (className !== q.className) { + throw new Error('All queries must be for the same class.'); + } + }); + + var query = new ParseQuery(className); + query._orQuery(queries); + return query; + } +} + +var DefaultController = { + find(className, params, options) { + var RESTController = CoreManager.getRESTController(); + + return RESTController.request('GET', 'classes/' + className, params, options); + } +}; + +CoreManager.setQueryController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseRelation.js b/lib/react-native/ParseRelation.js new file mode 100644 index 000000000..c07b48cc1 --- /dev/null +++ b/lib/react-native/ParseRelation.js @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import { RelationOp } from './ParseOp'; +import ParseObject from './ParseObject'; +import ParseQuery from './ParseQuery'; + +/** + * Creates a new Relation for the given parent object and key. This + * constructor should rarely be used directly, but rather created by + * Parse.Object.relation. + * @class Parse.Relation + * @constructor + * @param {Parse.Object} parent The parent of this relation. + * @param {String} key The key for this relation on the parent. + * + *

              + * A class that is used to access all of the children of a many-to-many + * relationship. Each instance of Parse.Relation is associated with a + * particular parent object and key. + *

              + */ +export default class ParseRelation { + + constructor(parent, key) { + this.parent = parent; + this.key = key; + this.targetClassName = null; + } + + /** + * Makes sure that this relation has the right parent and key. + */ + _ensureParentAndKey(parent, key) { + this.key = this.key || key; + if (this.key !== key) { + throw new Error('Internal Error. Relation retrieved from two different keys.'); + } + if (this.parent) { + if (this.parent.className !== parent.className) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + if (this.parent.id) { + if (this.parent.id !== parent.id) { + throw new Error('Internal Error. Relation retrieved from two different Objects.'); + } + } else if (parent.id) { + this.parent = parent; + } + } else { + this.parent = parent; + } + } + + /** + * Adds a Parse.Object or an array of Parse.Objects to the relation. + * @method add + * @param {} objects The item or items to add. + */ + add(objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new RelationOp(objects, []); + var parent = this.parent; + if (!parent) { + throw new Error('Cannot add to a Relation without a parent'); + } + parent.set(this.key, change); + this.targetClassName = change._targetClassName; + return parent; + } + + /** + * Removes a Parse.Object or an array of Parse.Objects from this relation. + * @method remove + * @param {} objects The item or items to remove. + */ + remove(objects) { + if (!Array.isArray(objects)) { + objects = [objects]; + } + + var change = new RelationOp([], objects); + if (!this.parent) { + throw new Error('Cannot remove from a Relation without a parent'); + } + this.parent.set(this.key, change); + this.targetClassName = change._targetClassName; + } + + /** + * Returns a JSON version of the object suitable for saving to disk. + * @method toJSON + * @return {Object} + */ + toJSON() { + return { + __type: 'Relation', + className: this.targetClassName + }; + } + + /** + * Returns a Parse.Query that is limited to objects in this + * relation. + * @method query + * @return {Parse.Query} + */ + query() { + var query; + var parent = this.parent; + if (!parent) { + throw new Error('Cannot construct a query for a Relation without a parent'); + } + if (!this.targetClassName) { + query = new ParseQuery(parent.className); + query._extraOptions.redirectClassNameForKey = this.key; + } else { + query = new ParseQuery(this.targetClassName); + } + query._addCondition('$relatedTo', 'object', { + __type: 'Pointer', + className: parent.className, + objectId: parent.id + }); + query._addCondition('$relatedTo', 'key', this.key); + + return query; + } +} \ No newline at end of file diff --git a/lib/react-native/ParseRole.js b/lib/react-native/ParseRole.js new file mode 100644 index 000000000..04164b2e4 --- /dev/null +++ b/lib/react-native/ParseRole.js @@ -0,0 +1,133 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseACL from './ParseACL'; +import ParseError from './ParseError'; +import ParseObject from './ParseObject'; + +/** + * Represents a Role on the Parse server. Roles represent groupings of + * Users for the purposes of granting permissions (e.g. specifying an ACL + * for an Object). Roles are specified by their sets of child users and + * child roles, all of which are granted any permissions that the parent + * role has. + * + *

              Roles must have a name (which cannot be changed after creation of the + * role), and must specify an ACL.

              + * @class Parse.Role + * @constructor + * @param {String} name The name of the Role to create. + * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. + * A Parse.Role is a local representation of a role persisted to the Parse + * cloud. + */ +export default class ParseRole extends ParseObject { + constructor(name, acl) { + super('_Role'); + if (typeof name === 'string' && acl instanceof ParseACL) { + this.setName(name); + this.setACL(acl); + } + } + + /** + * Gets the name of the role. You can alternatively call role.get("name") + * + * @method getName + * @return {String} the name of the role. + */ + getName() { + const name = this.get('name'); + if (name == null || typeof name === 'string') { + return name; + } + return ''; + } + + /** + * Sets the name for a role. This value must be set before the role has + * been saved to the server, and cannot be set once the role has been + * saved. + * + *

              + * A role's name can only contain alphanumeric characters, _, -, and + * spaces. + *

              + * + *

              This is equivalent to calling role.set("name", name)

              + * + * @method setName + * @param {String} name The name of the role. + * @param {Object} options Standard options object with success and error + * callbacks. + */ + setName(name, options) { + return this.set('name', name, options); + } + + /** + * Gets the Parse.Relation for the Parse.Users that are direct + * children of this role. These users are granted any privileges that this + * role has been granted (e.g. read or write access through ACLs). You can + * add or remove users from the role through this relation. + * + *

              This is equivalent to calling role.relation("users")

              + * + * @method getUsers + * @return {Parse.Relation} the relation for the users belonging to this + * role. + */ + getUsers() { + return this.relation('users'); + } + + /** + * Gets the Parse.Relation for the Parse.Roles that are direct + * children of this role. These roles' users are granted any privileges that + * this role has been granted (e.g. read or write access through ACLs). You + * can add or remove child roles from this role through this relation. + * + *

              This is equivalent to calling role.relation("roles")

              + * + * @method getRoles + * @return {Parse.Relation} the relation for the roles belonging to this + * role. + */ + getRoles() { + return this.relation('roles'); + } + + validate(attrs, options) { + var isInvalid = super.validate(attrs, options); + if (isInvalid) { + return isInvalid; + } + + if ('name' in attrs && attrs.name !== this.getName()) { + var newName = attrs.name; + if (this.id && this.id !== attrs.objectId) { + // Check to see if the objectId being set matches this.id + // This happens during a fetch -- the id is set before calling fetch + // Let the name be set in this case + return new ParseError(ParseError.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); + } + if (typeof newName !== 'string') { + return new ParseError(ParseError.OTHER_CAUSE, 'A role\'s name must be a String.'); + } + if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { + return new ParseError(ParseError.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); + } + } + return false; + } +} + +ParseObject.registerSubclass('_Role', ParseRole); \ No newline at end of file diff --git a/lib/react-native/ParseSession.js b/lib/react-native/ParseSession.js new file mode 100644 index 000000000..f1554fc9a --- /dev/null +++ b/lib/react-native/ParseSession.js @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import isRevocableSession from './isRevocableSession'; +import ParseObject from './ParseObject'; +import ParsePromise from './ParsePromise'; +import ParseUser from './ParseUser'; + +/** + * @class Parse.Session + * @constructor + * + *

              A Parse.Session object is a local representation of a revocable session. + * This class is a subclass of a Parse.Object, and retains the same + * functionality of a Parse.Object.

              + */ +export default class ParseSession extends ParseObject { + constructor(attributes) { + super('_Session'); + if (attributes && typeof attributes === 'object') { + if (!this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Session'); + } + } + } + + /** + * Returns the session token string. + * @method getSessionToken + * @return {String} + */ + getSessionToken() { + const token = this.get('sessionToken'); + if (typeof token === 'string') { + return token; + } + return ''; + } + + static readOnlyAttributes() { + return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; + } + + /** + * Retrieves the Session object for the currently logged in session. + * @method current + * @static + * @return {Parse.Promise} A promise that is resolved with the Parse.Session + * object after it has been fetched. If there is no current user, the + * promise will be rejected. + */ + static current(options) { + options = options || {}; + var controller = CoreManager.getSessionController(); + + var sessionOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + sessionOptions.useMasterKey = options.useMasterKey; + } + return ParseUser.currentAsync().then(user => { + if (!user) { + return ParsePromise.error('There is no current user.'); + } + user.getSessionToken(); + + sessionOptions.sessionToken = user.getSessionToken(); + return controller.getSession(sessionOptions); + }); + } + + /** + * Determines whether the current session token is revocable. + * This method is useful for migrating Express.js or Node.js web apps to + * use revocable sessions. If you are migrating an app that uses the Parse + * SDK in the browser only, please use Parse.User.enableRevocableSession() + * instead, so that sessions can be automatically upgraded. + * @method isCurrentSessionRevocable + * @static + * @return {Boolean} + */ + static isCurrentSessionRevocable() { + var currentUser = ParseUser.current(); + if (currentUser) { + return isRevocableSession(currentUser.getSessionToken() || ''); + } + return false; + } +} + +ParseObject.registerSubclass('_Session', ParseSession); + +var DefaultController = { + getSession(options) { + var RESTController = CoreManager.getRESTController(); + var session = new ParseSession(); + + return RESTController.request('GET', 'sessions/me', {}, options).then(sessionData => { + session._finishFetch(sessionData); + session._setExisted(true); + return session; + }); + } +}; + +CoreManager.setSessionController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseUser.js b/lib/react-native/ParseUser.js new file mode 100644 index 000000000..129c4cfbb --- /dev/null +++ b/lib/react-native/ParseUser.js @@ -0,0 +1,952 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import isRevocableSession from './isRevocableSession'; +import ParseError from './ParseError'; +import ParseObject from './ParseObject'; +import ParsePromise from './ParsePromise'; +import ParseSession from './ParseSession'; +import Storage from './Storage'; + +var CURRENT_USER_KEY = 'currentUser'; +var canUseCurrentUser = !CoreManager.get('IS_NODE'); +var currentUserCacheMatchesDisk = false; +var currentUserCache = null; + +var authProviders = {}; + +/** + * @class Parse.User + * @constructor + * + *

              A Parse.User object is a local representation of a user persisted to the + * Parse cloud. This class is a subclass of a Parse.Object, and retains the + * same functionality of a Parse.Object, but also extends it with various + * user specific methods, like authentication, signing up, and validation of + * uniqueness.

              + */ +export default class ParseUser extends ParseObject { + constructor(attributes) { + super('_User'); + if (attributes && typeof attributes === 'object') { + if (!this.set(attributes || {})) { + throw new Error('Can\'t create an invalid Parse User'); + } + } + } + + /** + * Request a revocable session token to replace the older style of token. + * @method _upgradeToRevocableSession + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is resolved when the replacement + * token has been fetched. + */ + _upgradeToRevocableSession(options) { + options = options || {}; + + var upgradeOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + upgradeOptions.useMasterKey = options.useMasterKey; + } + + var controller = CoreManager.getUserController(); + return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); + } + + /** + * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can + * call linkWith on the user (even if it doesn't exist yet on the server). + * @method _linkWith + */ + _linkWith(provider, options) { + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[provider]; + } else { + authType = provider.getAuthType(); + } + if (options && options.hasOwnProperty('authData')) { + var authData = this.get('authData') || {}; + if (typeof authData !== 'object') { + throw new Error('Invalid type: authData field should be an object'); + } + authData[authType] = options.authData; + + var controller = CoreManager.getUserController(); + return controller.linkWith(this, authData)._thenRunCallbacks(options, this); + } else { + var promise = new ParsePromise(); + provider.authenticate({ + success: (provider, result) => { + var opts = {}; + opts.authData = result; + if (options.success) { + opts.success = options.success; + } + if (options.error) { + opts.error = options.error; + } + this._linkWith(provider, opts).then(() => { + promise.resolve(this); + }, error => { + promise.reject(error); + }); + }, + error: (provider, error) => { + if (typeof options.error === 'function') { + options.error(this, error); + } + promise.reject(error); + } + }); + return promise; + } + } + + /** + * Synchronizes auth data for a provider (e.g. puts the access token in the + * right place to be used by the Facebook SDK). + * @method _synchronizeAuthData + */ + _synchronizeAuthData(provider) { + if (!this.isCurrent() || !provider) { + return; + } + var authType; + if (typeof provider === 'string') { + authType = provider; + provider = authProviders[authType]; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData'); + if (!provider || !authData || typeof authData !== 'object') { + return; + } + var success = provider.restoreAuthentication(authData[authType]); + if (!success) { + this._unlinkFrom(provider); + } + } + + /** + * Synchronizes authData for all providers. + * @method _synchronizeAllAuthData + */ + _synchronizeAllAuthData() { + var authData = this.get('authData'); + if (typeof authData !== 'object') { + return; + } + + for (var key in authData) { + this._synchronizeAuthData(key); + } + } + + /** + * Removes null values from authData (which exist temporarily for + * unlinking) + * @method _cleanupAuthData + */ + _cleanupAuthData() { + if (!this.isCurrent()) { + return; + } + var authData = this.get('authData'); + if (typeof authData !== 'object') { + return; + } + + for (var key in authData) { + if (!authData[key]) { + delete authData[key]; + } + } + } + + /** + * Unlinks a user from a service. + * @method _unlinkFrom + */ + _unlinkFrom(provider, options) { + if (typeof provider === 'string') { + provider = authProviders[provider]; + } else { + provider.getAuthType(); + } + return this._linkWith(provider, { authData: null }).then(() => { + this._synchronizeAuthData(provider); + return ParsePromise.as(this); + })._thenRunCallbacks(options); + } + + /** + * Checks whether a user is linked to a service. + * @method _isLinked + */ + _isLinked(provider) { + var authType; + if (typeof provider === 'string') { + authType = provider; + } else { + authType = provider.getAuthType(); + } + var authData = this.get('authData') || {}; + if (typeof authData !== 'object') { + return false; + } + return !!authData[authType]; + } + + /** + * Deauthenticates all providers. + * @method _logOutWithAll + */ + _logOutWithAll() { + var authData = this.get('authData'); + if (typeof authData !== 'object') { + return; + } + + for (var key in authData) { + this._logOutWith(key); + } + } + + /** + * Deauthenticates a single provider (e.g. removing access tokens from the + * Facebook SDK). + * @method _logOutWith + */ + _logOutWith(provider) { + if (!this.isCurrent()) { + return; + } + if (typeof provider === 'string') { + provider = authProviders[provider]; + } + if (provider && provider.deauthenticate) { + provider.deauthenticate(); + } + } + + /** + * Class instance method used to maintain specific keys when a fetch occurs. + * Used to ensure that the session token is not lost. + */ + _preserveFieldsOnFetch() { + return { + sessionToken: this.get('sessionToken') + }; + } + + /** + * Returns true if current would return this user. + * @method isCurrent + * @return {Boolean} + */ + isCurrent() { + var current = ParseUser.current(); + return !!current && current.id === this.id; + } + + /** + * Returns get("username"). + * @method getUsername + * @return {String} + */ + getUsername() { + const username = this.get('username'); + if (username == null || typeof username === 'string') { + return username; + } + return ''; + } + + /** + * Calls set("username", username, options) and returns the result. + * @method setUsername + * @param {String} username + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + setUsername(username) { + // Strip anonymity, even we do not support anonymous user in js SDK, we may + // encounter anonymous user created by android/iOS in cloud code. + var authData = this.get('authData'); + if (authData && typeof authData === 'object' && authData.hasOwnProperty('anonymous')) { + // We need to set anonymous to null instead of deleting it in order to remove it from Parse. + authData.anonymous = null; + } + this.set('username', username); + } + + /** + * Calls set("password", password, options) and returns the result. + * @method setPassword + * @param {String} password + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + setPassword(password) { + this.set('password', password); + } + + /** + * Returns get("email"). + * @method getEmail + * @return {String} + */ + getEmail() { + const email = this.get('email'); + if (email == null || typeof email === 'string') { + return email; + } + return ''; + } + + /** + * Calls set("email", email, options) and returns the result. + * @method setEmail + * @param {String} email + * @param {Object} options A Backbone-style options object. + * @return {Boolean} + */ + setEmail(email) { + this.set('email', email); + } + + /** + * Returns the session token for this user, if the user has been logged in, + * or if it is the result of a query with the master key. Otherwise, returns + * undefined. + * @method getSessionToken + * @return {String} the session token, or undefined + */ + getSessionToken() { + const token = this.get('sessionToken'); + if (token == null || typeof token === 'string') { + return token; + } + return ''; + } + + /** + * Checks whether this user is the current user and has been authenticated. + * @method authenticated + * @return (Boolean) whether this user is the current user and is logged in. + */ + authenticated() { + var current = ParseUser.current(); + return !!this.get('sessionToken') && !!current && current.id === this.id; + } + + /** + * Signs up a new user. You should call this instead of save for + * new Parse.Users. This will create a new Parse.User on the server, and + * also persist the session on disk so that you can access the user using + * current. + * + *

              A username and password must be set before calling signUp.

              + * + *

              Calls options.success or options.error on completion.

              + * + * @method signUp + * @param {Object} attrs Extra fields to set on the new user, or null. + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled when the signup + * finishes. + */ + signUp(attrs, options) { + options = options || {}; + + var signupOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + signupOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + signupOptions.installationId = options.installationId; + } + + var controller = CoreManager.getUserController(); + return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); + } + + /** + * Logs in a Parse.User. On success, this saves the session to disk, + * so you can retrieve the currently logged in user using + * current. + * + *

              A username and password must be set before calling logIn.

              + * + *

              Calls options.success or options.error on completion.

              + * + * @method logIn + * @param {Object} options A Backbone-style options object. + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login is complete. + */ + logIn(options) { + options = options || {}; + + var loginOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + loginOptions.useMasterKey = options.useMasterKey; + } + if (options.hasOwnProperty('installationId')) { + loginOptions.installationId = options.installationId; + } + + var controller = CoreManager.getUserController(); + return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); + } + + /** + * Wrap the default save behavior with functionality to save to local + * storage if this is current user. + */ + save(...args) { + return super.save.apply(this, args).then(() => { + if (this.isCurrent()) { + return CoreManager.getUserController().updateUserOnDisk(this); + } + return this; + }); + } + + /** + * Wrap the default destroy behavior with functionality that logs out + * the current user when it is destroyed + */ + destroy(...args) { + return super.destroy.apply(this, args).then(() => { + if (this.isCurrent()) { + return CoreManager.getUserController().removeUserFromDisk(); + } + return this; + }); + } + + /** + * Wrap the default fetch behavior with functionality to save to local + * storage if this is current user. + */ + fetch(...args) { + return super.fetch.apply(this, args).then(() => { + if (this.isCurrent()) { + return CoreManager.getUserController().updateUserOnDisk(this); + } + return this; + }); + } + + static readOnlyAttributes() { + return ['sessionToken']; + } + + /** + * Adds functionality to the existing Parse.User class + * @method extend + * @param {Object} protoProps A set of properties to add to the prototype + * @param {Object} classProps A set of static properties to add to the class + * @static + * @return {Class} The newly extended Parse.User class + */ + static extend(protoProps, classProps) { + if (protoProps) { + for (var prop in protoProps) { + if (prop !== 'className') { + Object.defineProperty(ParseUser.prototype, prop, { + value: protoProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + if (classProps) { + for (var prop in classProps) { + if (prop !== 'className') { + Object.defineProperty(ParseUser, prop, { + value: classProps[prop], + enumerable: false, + writable: true, + configurable: true + }); + } + } + } + + return ParseUser; + } + + /** + * Retrieves the currently logged in ParseUser with a valid session, + * either from memory or localStorage, if necessary. + * @method current + * @static + * @return {Parse.Object} The currently logged in Parse.User. + */ + static current() { + if (!canUseCurrentUser) { + return null; + } + var controller = CoreManager.getUserController(); + return controller.currentUser(); + } + + /** + * Retrieves the currently logged in ParseUser from asynchronous Storage. + * @method currentAsync + * @static + * @return {Parse.Promise} A Promise that is resolved with the currently + * logged in Parse User + */ + static currentAsync() { + if (!canUseCurrentUser) { + return ParsePromise.as(null); + } + var controller = CoreManager.getUserController(); + return controller.currentUserAsync(); + } + + /** + * Signs up a new user with a username (or email) and password. + * This will create a new Parse.User on the server, and also persist the + * session in localStorage so that you can access the user using + * {@link #current}. + * + *

              Calls options.success or options.error on completion.

              + * + * @method signUp + * @param {String} username The username (or email) to sign up with. + * @param {String} password The password to sign up with. + * @param {Object} attrs Extra fields to set on the new user. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the signup completes. + */ + static signUp(username, password, attrs, options) { + attrs = attrs || {}; + attrs.username = username; + attrs.password = password; + var user = new ParseUser(attrs); + return user.signUp({}, options); + } + + /** + * Logs in a user with a username (or email) and password. On success, this + * saves the session to disk, so you can retrieve the currently logged in + * user using current. + * + *

              Calls options.success or options.error on completion.

              + * + * @method logIn + * @param {String} username The username (or email) to log in with. + * @param {String} password The password to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + static logIn(username, password, options) { + if (typeof username !== 'string') { + return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); + } else if (typeof password !== 'string') { + return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Password must be a string.')); + } + var user = new ParseUser(); + user._finishFetch({ username: username, password: password }); + return user.logIn(options); + } + + /** + * Logs in a user with a session token. On success, this saves the session + * to disk, so you can retrieve the currently logged in user using + * current. + * + *

              Calls options.success or options.error on completion.

              + * + * @method become + * @param {String} sessionToken The sessionToken to log in with. + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is fulfilled with the user when + * the login completes. + */ + static become(sessionToken, options) { + if (!canUseCurrentUser) { + throw new Error('It is not memory-safe to become a user in a server environment'); + } + options = options || {}; + + var becomeOptions = { + sessionToken: sessionToken + }; + if (options.hasOwnProperty('useMasterKey')) { + becomeOptions.useMasterKey = options.useMasterKey; + } + + var controller = CoreManager.getUserController(); + return controller.become(becomeOptions)._thenRunCallbacks(options); + } + + static logInWith(provider, options) { + return ParseUser._logInWith(provider, options); + } + + /** + * Logs out the currently logged in user session. This will remove the + * session from disk, log out of linked services, and future calls to + * current will return null. + * @method logOut + * @static + * @return {Parse.Promise} A promise that is resolved when the session is + * destroyed on the server. + */ + static logOut() { + if (!canUseCurrentUser) { + throw new Error('There is no current user user on a node.js server environment.'); + } + + var controller = CoreManager.getUserController(); + return controller.logOut(); + } + + /** + * Requests a password reset email to be sent to the specified email address + * associated with the user account. This email allows the user to securely + * reset their password on the Parse site. + * + *

              Calls options.success or options.error on completion.

              + * + * @method requestPasswordReset + * @param {String} email The email address associated with the user that + * forgot their password. + * @param {Object} options A Backbone-style options object. + * @static + */ + static requestPasswordReset(email, options) { + options = options || {}; + + var requestOptions = {}; + if (options.hasOwnProperty('useMasterKey')) { + requestOptions.useMasterKey = options.useMasterKey; + } + + var controller = CoreManager.getUserController(); + return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); + } + + /** + * Allow someone to define a custom User class without className + * being rewritten to _User. The default behavior is to rewrite + * User to _User for legacy reasons. This allows developers to + * override that behavior. + * + * @method allowCustomUserClass + * @param {Boolean} isAllowed Whether or not to allow custom User class + * @static + */ + static allowCustomUserClass(isAllowed) { + CoreManager.set('PERFORM_USER_REWRITE', !isAllowed); + } + + /** + * Allows a legacy application to start using revocable sessions. If the + * current session token is not revocable, a request will be made for a new, + * revocable session. + * It is not necessary to call this method from cloud code unless you are + * handling user signup or login from the server side. In a cloud code call, + * this function will not attempt to upgrade the current token. + * @method enableRevocableSession + * @param {Object} options A Backbone-style options object. + * @static + * @return {Parse.Promise} A promise that is resolved when the process has + * completed. If a replacement session token is requested, the promise + * will be resolved after a new token has been fetched. + */ + static enableRevocableSession(options) { + options = options || {}; + CoreManager.set('FORCE_REVOCABLE_SESSION', true); + if (canUseCurrentUser) { + var current = ParseUser.current(); + if (current) { + return current._upgradeToRevocableSession(options); + } + } + return ParsePromise.as()._thenRunCallbacks(options); + } + + /** + * Enables the use of become or the current user in a server + * environment. These features are disabled by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method enableUnsafeCurrentUser + * @static + */ + static enableUnsafeCurrentUser() { + canUseCurrentUser = true; + } + + /** + * Disables the use of become or the current user in any environment. + * These features are disabled on servers by default, since they depend on + * global objects that are not memory-safe for most servers. + * @method disableUnsafeCurrentUser + * @static + */ + static disableUnsafeCurrentUser() { + canUseCurrentUser = false; + } + + static _registerAuthenticationProvider(provider) { + authProviders[provider.getAuthType()] = provider; + // Synchronize the current user with the auth provider. + ParseUser.currentAsync().then(current => { + if (current) { + current._synchronizeAuthData(provider.getAuthType()); + } + }); + } + + static _logInWith(provider, options) { + var user = new ParseUser(); + return user._linkWith(provider, options); + } + + static _clearCache() { + currentUserCache = null; + currentUserCacheMatchesDisk = false; + } + + static _setCurrentUserCache(user) { + currentUserCache = user; + } +} + +ParseObject.registerSubclass('_User', ParseUser); + +var DefaultController = { + updateUserOnDisk(user) { + var path = Storage.generatePath(CURRENT_USER_KEY); + var json = user.toJSON(); + json.className = '_User'; + return Storage.setItemAsync(path, JSON.stringify(json)).then(() => { + return user; + }); + }, + + removeUserFromDisk() { + let path = Storage.generatePath(CURRENT_USER_KEY); + currentUserCacheMatchesDisk = true; + currentUserCache = null; + return Storage.removeItemAsync(path); + }, + + setCurrentUser(user) { + currentUserCache = user; + user._cleanupAuthData(); + user._synchronizeAllAuthData(); + return DefaultController.updateUserOnDisk(user); + }, + + currentUser() { + if (currentUserCache) { + return currentUserCache; + } + if (currentUserCacheMatchesDisk) { + return null; + } + if (Storage.async()) { + throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); + } + var path = Storage.generatePath(CURRENT_USER_KEY); + var userData = Storage.getItem(path); + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return null; + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = ParseObject.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return current; + }, + + currentUserAsync() { + if (currentUserCache) { + return ParsePromise.as(currentUserCache); + } + if (currentUserCacheMatchesDisk) { + return ParsePromise.as(null); + } + var path = Storage.generatePath(CURRENT_USER_KEY); + return Storage.getItemAsync(path).then(userData => { + currentUserCacheMatchesDisk = true; + if (!userData) { + currentUserCache = null; + return ParsePromise.as(null); + } + userData = JSON.parse(userData); + if (!userData.className) { + userData.className = '_User'; + } + if (userData._id) { + if (userData.objectId !== userData._id) { + userData.objectId = userData._id; + } + delete userData._id; + } + if (userData._sessionToken) { + userData.sessionToken = userData._sessionToken; + delete userData._sessionToken; + } + var current = ParseObject.fromJSON(userData); + currentUserCache = current; + current._synchronizeAllAuthData(); + return ParsePromise.as(current); + }); + }, + + signUp(user, attrs, options) { + var username = attrs && attrs.username || user.get('username'); + var password = attrs && attrs.password || user.get('password'); + + if (!username || !username.length) { + return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); + } + if (!password || !password.length) { + return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); + } + + return user.save(attrs, options).then(() => { + // Clear the password field + user._finishFetch({ password: undefined }); + + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + }, + + logIn(user, options) { + var RESTController = CoreManager.getRESTController(); + var stateController = CoreManager.getObjectStateController(); + var auth = { + username: user.get('username'), + password: user.get('password') + }; + return RESTController.request('GET', 'login', auth, options).then((response, status) => { + user._migrateId(response.objectId); + user._setExisted(true); + stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); + stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); + response.password = undefined; + user._finishFetch(response); + if (!canUseCurrentUser) { + // We can't set the current user, so just return the one we logged in + return ParsePromise.as(user); + } + return DefaultController.setCurrentUser(user); + }); + }, + + become(options) { + var user = new ParseUser(); + var RESTController = CoreManager.getRESTController(); + return RESTController.request('GET', 'users/me', {}, options).then((response, status) => { + user._finishFetch(response); + user._setExisted(true); + return DefaultController.setCurrentUser(user); + }); + }, + + logOut() { + return DefaultController.currentUserAsync().then(currentUser => { + var path = Storage.generatePath(CURRENT_USER_KEY); + var promise = Storage.removeItemAsync(path); + var RESTController = CoreManager.getRESTController(); + if (currentUser !== null) { + var currentSession = currentUser.getSessionToken(); + if (currentSession && isRevocableSession(currentSession)) { + promise = promise.then(() => { + return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); + }); + } + currentUser._logOutWithAll(); + currentUser._finishFetch({ sessionToken: undefined }); + } + currentUserCacheMatchesDisk = true; + currentUserCache = null; + + return promise; + }); + }, + + requestPasswordReset(email, options) { + var RESTController = CoreManager.getRESTController(); + return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); + }, + + upgradeToRevocableSession(user, options) { + var token = user.getSessionToken(); + if (!token) { + return ParsePromise.error(new ParseError(ParseError.SESSION_MISSING, 'Cannot upgrade a user with no session token')); + } + + options.sessionToken = token; + + var RESTController = CoreManager.getRESTController(); + return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(result => { + var session = new ParseSession(); + session._finishFetch(result); + user._finishFetch({ sessionToken: session.getSessionToken() }); + if (user.isCurrent()) { + return DefaultController.setCurrentUser(user); + } + return ParsePromise.as(user); + }); + }, + + linkWith(user, authData) { + return user.save({ authData }).then(() => { + if (canUseCurrentUser) { + return DefaultController.setCurrentUser(user); + } + return user; + }); + } +}; + +CoreManager.setUserController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/Push.js b/lib/react-native/Push.js new file mode 100644 index 000000000..2710abe4d --- /dev/null +++ b/lib/react-native/Push.js @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import ParseQuery from './ParseQuery'; + +/** + * Contains functions to deal with Push in Parse. + * @class Parse.Push + * @static + */ + +/** + * Sends a push notification. + * @method send + * @param {Object} data - The data of the push notification. Valid fields + * are: + *
                + *
              1. channels - An Array of channels to push to.
              2. + *
              3. push_time - A Date object for when to send the push.
              4. + *
              5. expiration_time - A Date object for when to expire + * the push.
              6. + *
              7. expiration_interval - The seconds from now to expire the push.
              8. + *
              9. where - A Parse.Query over Parse.Installation that is used to match + * a set of installations to push to.
              10. + *
              11. data - The data to send as part of the push
              12. + *
                  + * @param {Object} options An object that has an optional success function, + * that takes no arguments and will be called on a successful push, and + * an error function that takes a Parse.Error and will be called if the push + * failed. + * @return {Parse.Promise} A promise that is fulfilled when the push request + * completes. + */ +export function send(data, options) { + options = options || {}; + + if (data.where && data.where instanceof ParseQuery) { + data.where = data.where.toJSON().where; + } + + if (data.push_time && typeof data.push_time === 'object') { + data.push_time = data.push_time.toJSON(); + } + + if (data.expiration_time && typeof data.expiration_time === 'object') { + data.expiration_time = data.expiration_time.toJSON(); + } + + if (data.expiration_time && data.expiration_interval) { + throw new Error('expiration_time and expiration_interval cannot both be set.'); + } + + return CoreManager.getPushController().send(data, { + useMasterKey: options.useMasterKey + })._thenRunCallbacks(options); +} + +var DefaultController = { + send(data, options) { + var RESTController = CoreManager.getRESTController(); + + var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); + + return request._thenRunCallbacks(options); + } +}; + +CoreManager.setPushController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/RESTController.js b/lib/react-native/RESTController.js new file mode 100644 index 000000000..89ee421a0 --- /dev/null +++ b/lib/react-native/RESTController.js @@ -0,0 +1,226 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import ParseError from './ParseError'; +import ParsePromise from './ParsePromise'; +import Storage from './Storage'; + +var XHR = null; +if (typeof XMLHttpRequest !== 'undefined') { + XHR = XMLHttpRequest; +} + + +var useXDomainRequest = false; +if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { + useXDomainRequest = true; +} + +function ajaxIE9(method, url, data) { + var promise = new ParsePromise(); + var xdr = new XDomainRequest(); + xdr.onload = function () { + var response; + try { + response = JSON.parse(xdr.responseText); + } catch (e) { + promise.reject(e); + } + if (response) { + promise.resolve(response); + } + }; + xdr.onerror = xdr.ontimeout = function () { + // Let's fake a real error message. + var fakeResponse = { + responseText: JSON.stringify({ + code: ParseError.X_DOMAIN_REQUEST, + error: 'IE\'s XDomainRequest does not supply error info.' + }) + }; + promise.reject(fakeResponse); + }; + xdr.onprogress = function () {}; + xdr.open(method, url); + xdr.send(data); + return promise; +} + +const RESTController = { + ajax(method, url, data, headers) { + if (useXDomainRequest) { + return ajaxIE9(method, url, data, headers); + } + + var promise = new ParsePromise(); + var attempts = 0; + + var dispatch = function () { + if (XHR == null) { + throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); + } + var handled = false; + var xhr = new XHR(); + + xhr.onreadystatechange = function () { + if (xhr.readyState !== 4 || handled) { + return; + } + handled = true; + + if (xhr.status >= 200 && xhr.status < 300) { + var response; + try { + response = JSON.parse(xhr.responseText); + } catch (e) { + promise.reject(e.toString()); + } + if (response) { + promise.resolve(response, xhr.status, xhr); + } + } else if (xhr.status >= 500 || xhr.status === 0) { + // retry on 5XX or node-xmlhttprequest error + if (++attempts < CoreManager.get('REQUEST_ATTEMPT_LIMIT')) { + // Exponentially-growing random delay + var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); + setTimeout(dispatch, delay); + } else if (xhr.status === 0) { + promise.reject('Unable to connect to the Parse API'); + } else { + // After the retry limit is reached, fail + promise.reject(xhr); + } + } else { + promise.reject(xhr); + } + }; + + headers = headers || {}; + if (typeof headers['Content-Type'] !== 'string') { + headers['Content-Type'] = 'text/plain'; // Avoid pre-flight + } + if (CoreManager.get('IS_NODE')) { + headers['User-Agent'] = 'Parse/' + CoreManager.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; + } + + xhr.open(method, url, true); + for (var h in headers) { + xhr.setRequestHeader(h, headers[h]); + } + xhr.send(data); + }; + dispatch(); + + return promise; + }, + + request(method, path, data, options) { + options = options || {}; + var url = CoreManager.get('SERVER_URL'); + if (url[url.length - 1] !== '/') { + url += '/'; + } + url += path; + + var payload = {}; + if (data && typeof data === 'object') { + for (var k in data) { + payload[k] = data[k]; + } + } + + if (method !== 'POST') { + payload._method = method; + method = 'POST'; + } + + payload._ApplicationId = CoreManager.get('APPLICATION_ID'); + let jsKey = CoreManager.get('JAVASCRIPT_KEY'); + if (jsKey) { + payload._JavaScriptKey = jsKey; + } + payload._ClientVersion = CoreManager.get('VERSION'); + + var useMasterKey = options.useMasterKey; + if (typeof useMasterKey === 'undefined') { + useMasterKey = CoreManager.get('USE_MASTER_KEY'); + } + if (useMasterKey) { + if (CoreManager.get('MASTER_KEY')) { + delete payload._JavaScriptKey; + payload._MasterKey = CoreManager.get('MASTER_KEY'); + } else { + throw new Error('Cannot use the Master Key, it has not been provided.'); + } + } + + if (CoreManager.get('FORCE_REVOCABLE_SESSION')) { + payload._RevocableSession = '1'; + } + + var installationId = options.installationId; + var installationIdPromise; + if (installationId && typeof installationId === 'string') { + installationIdPromise = ParsePromise.as(installationId); + } else { + var installationController = CoreManager.getInstallationController(); + installationIdPromise = installationController.currentInstallationId(); + } + + return installationIdPromise.then(iid => { + payload._InstallationId = iid; + var userController = CoreManager.getUserController(); + if (options && typeof options.sessionToken === 'string') { + return ParsePromise.as(options.sessionToken); + } else if (userController) { + return userController.currentUserAsync().then(user => { + if (user) { + return ParsePromise.as(user.getSessionToken()); + } + return ParsePromise.as(null); + }); + } + return ParsePromise.as(null); + }).then(token => { + if (token) { + payload._SessionToken = token; + } + + var payloadString = JSON.stringify(payload); + + return RESTController.ajax(method, url, payloadString); + }).then(null, function (response) { + // Transform the error into an instance of ParseError by trying to parse + // the error string as JSON + var error; + if (response && response.responseText) { + try { + var errorJSON = JSON.parse(response.responseText); + error = new ParseError(errorJSON.code, errorJSON.error); + } catch (e) { + // If we fail to parse the error text, that's okay. + error = new ParseError(ParseError.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); + } + } else { + error = new ParseError(ParseError.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + JSON.stringify(response)); + } + + return ParsePromise.error(error); + }); + }, + + _setXHR(xhr) { + XHR = xhr; + } +}; + +module.exports = RESTController; \ No newline at end of file diff --git a/lib/react-native/SingleInstanceStateController.js b/lib/react-native/SingleInstanceStateController.js new file mode 100644 index 000000000..2f57854d7 --- /dev/null +++ b/lib/react-native/SingleInstanceStateController.js @@ -0,0 +1,125 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import * as ObjectStateMutations from './ObjectStateMutations'; + +let objectState = {}; + +export function getState(obj) { + let classData = objectState[obj.className]; + if (classData) { + return classData[obj.id] || null; + } + return null; +} + +export function initializeState(obj, initial) { + let state = getState(obj); + if (state) { + return state; + } + if (!objectState[obj.className]) { + objectState[obj.className] = {}; + } + if (!initial) { + initial = ObjectStateMutations.defaultState(); + } + state = objectState[obj.className][obj.id] = initial; + return state; +} + +export function removeState(obj) { + let state = getState(obj); + if (state === null) { + return null; + } + delete objectState[obj.className][obj.id]; + return state; +} + +export function getServerData(obj) { + let state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +export function setServerData(obj, attributes) { + let serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +export function getPendingOps(obj) { + let state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +export function setPendingOp(obj, attr, op) { + let pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +export function pushPendingState(obj) { + let pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +export function popPendingState(obj) { + let pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +export function mergeFirstPendingState(obj) { + let pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +export function getObjectCache(obj) { + let state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +export function estimateAttribute(obj, attr) { + let serverData = getServerData(obj); + let pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +export function estimateAttributes(obj) { + let serverData = getServerData(obj); + let pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +export function commitServerChanges(obj, changes) { + let state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +export function enqueueTask(obj, task) { + let state = initializeState(obj); + return state.tasks.enqueue(task); +} + +export function clearAllState() { + objectState = {}; +} + +export function duplicateState(source, dest) { + dest.id = source.id; +} \ No newline at end of file diff --git a/lib/react-native/Storage.js b/lib/react-native/Storage.js new file mode 100644 index 000000000..2bfa47412 --- /dev/null +++ b/lib/react-native/Storage.js @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import CoreManager from './CoreManager'; +import ParsePromise from './ParsePromise'; + +var Storage = { + async() { + var controller = CoreManager.getStorageController(); + return !!controller.async; + }, + + getItem(path) { + var controller = CoreManager.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.getItem(path); + }, + + getItemAsync(path) { + var controller = CoreManager.getStorageController(); + if (controller.async === 1) { + return controller.getItemAsync(path); + } + return ParsePromise.as(controller.getItem(path)); + }, + + setItem(path, value) { + var controller = CoreManager.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.setItem(path, value); + }, + + setItemAsync(path, value) { + var controller = CoreManager.getStorageController(); + if (controller.async === 1) { + return controller.setItemAsync(path, value); + } + return ParsePromise.as(controller.setItem(path, value)); + }, + + removeItem(path) { + var controller = CoreManager.getStorageController(); + if (controller.async === 1) { + throw new Error('Synchronous storage is not supported by the current storage controller'); + } + return controller.removeItem(path); + }, + + removeItemAsync(path) { + var controller = CoreManager.getStorageController(); + if (controller.async === 1) { + return controller.removeItemAsync(path); + } + return ParsePromise.as(controller.removeItem(path)); + }, + + generatePath(path) { + if (!CoreManager.get('APPLICATION_ID')) { + throw new Error('You need to call Parse.initialize before using Parse.'); + } + if (typeof path !== 'string') { + throw new Error('Tried to get a Storage path that was not a String.'); + } + if (path[0] === '/') { + path = path.substr(1); + } + return 'Parse/' + CoreManager.get('APPLICATION_ID') + '/' + path; + }, + + _clear() { + var controller = CoreManager.getStorageController(); + if (controller.hasOwnProperty('clear')) { + controller.clear(); + } + } +}; + +module.exports = Storage; + +CoreManager.setStorageController(require('./StorageController.react-native')); \ No newline at end of file diff --git a/lib/react-native/StorageController.browser.js b/lib/react-native/StorageController.browser.js new file mode 100644 index 000000000..84af3ccee --- /dev/null +++ b/lib/react-native/StorageController.browser.js @@ -0,0 +1,38 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParsePromise from './ParsePromise'; + +var StorageController = { + async: 0, + + getItem(path) { + return localStorage.getItem(path); + }, + + setItem(path, value) { + try { + localStorage.setItem(path, value); + } catch (e) { + // Quota exceeded, possibly due to Safari Private Browsing mode + } + }, + + removeItem(path) { + localStorage.removeItem(path); + }, + + clear() { + localStorage.clear(); + } +}; + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/react-native/StorageController.default.js b/lib/react-native/StorageController.default.js new file mode 100644 index 000000000..ded857850 --- /dev/null +++ b/lib/react-native/StorageController.default.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +// When there is no native storage interface, we default to an in-memory map +var memMap = {}; +var StorageController = { + async: 0, + + getItem(path) { + if (memMap.hasOwnProperty(path)) { + return memMap[path]; + } + return null; + }, + + setItem(path, value) { + memMap[path] = String(value); + }, + + removeItem(path) { + delete memMap[path]; + }, + + clear() { + for (var key in memMap) { + if (memMap.hasOwnProperty(key)) { + delete memMap[key]; + } + } + } +}; + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/react-native/StorageController.react-native.js b/lib/react-native/StorageController.react-native.js new file mode 100644 index 000000000..68e04d768 --- /dev/null +++ b/lib/react-native/StorageController.react-native.js @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParsePromise from './ParsePromise'; +// RN packager nonsense +import { AsyncStorage } from 'react-native/Libraries/react-native/react-native.js'; + +var StorageController = { + async: 1, + + getItemAsync(path) { + var p = new ParsePromise(); + AsyncStorage.getItem(path, function (err, value) { + if (err) { + p.reject(err); + } else { + p.resolve(value); + } + }); + return p; + }, + + setItemAsync(path, value) { + var p = new ParsePromise(); + AsyncStorage.setItem(path, value, function (err) { + if (err) { + p.reject(err); + } else { + p.resolve(value); + } + }); + return p; + }, + + removeItemAsync(path) { + var p = new ParsePromise(); + AsyncStorage.removeItem(path, function (err) { + if (err) { + p.reject(err); + } else { + p.resolve(); + } + }); + return p; + }, + + clear() { + AsyncStorage.clear(); + } +}; + +module.exports = StorageController; \ No newline at end of file diff --git a/lib/react-native/TaskQueue.js b/lib/react-native/TaskQueue.js new file mode 100644 index 000000000..584168339 --- /dev/null +++ b/lib/react-native/TaskQueue.js @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParsePromise from './ParsePromise'; + +class TaskQueue { + + constructor() { + this.queue = []; + } + + enqueue(task) { + var taskComplete = new ParsePromise(); + this.queue.push({ + task: task, + _completion: taskComplete + }); + if (this.queue.length === 1) { + task().then(() => { + this._dequeue(); + taskComplete.resolve(); + }, error => { + this._dequeue(); + taskComplete.reject(error); + }); + } + return taskComplete; + } + + _dequeue() { + this.queue.shift(); + if (this.queue.length) { + var next = this.queue[0]; + next.task().then(() => { + this._dequeue(); + next._completion.resolve(); + }, error => { + this._dequeue(); + next._completion.reject(error); + }); + } + } +} + +module.exports = TaskQueue; \ No newline at end of file diff --git a/lib/react-native/UniqueInstanceStateController.js b/lib/react-native/UniqueInstanceStateController.js new file mode 100644 index 000000000..2b112e228 --- /dev/null +++ b/lib/react-native/UniqueInstanceStateController.js @@ -0,0 +1,140 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import * as ObjectStateMutations from './ObjectStateMutations'; +import TaskQueue from './TaskQueue'; + +let objectState = new WeakMap(); + +export function getState(obj) { + let classData = objectState.get(obj); + return classData || null; +} + +export function initializeState(obj, initial) { + let state = getState(obj); + if (state) { + return state; + } + if (!initial) { + initial = { + serverData: {}, + pendingOps: [{}], + objectCache: {}, + tasks: new TaskQueue(), + existed: false + }; + } + state = initial; + objectState.set(obj, state); + return state; +} + +export function removeState(obj) { + let state = getState(obj); + if (state === null) { + return null; + } + objectState.delete(obj); + return state; +} + +export function getServerData(obj) { + let state = getState(obj); + if (state) { + return state.serverData; + } + return {}; +} + +export function setServerData(obj, attributes) { + let serverData = initializeState(obj).serverData; + ObjectStateMutations.setServerData(serverData, attributes); +} + +export function getPendingOps(obj) { + let state = getState(obj); + if (state) { + return state.pendingOps; + } + return [{}]; +} + +export function setPendingOp(obj, attr, op) { + let pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.setPendingOp(pendingOps, attr, op); +} + +export function pushPendingState(obj) { + let pendingOps = initializeState(obj).pendingOps; + ObjectStateMutations.pushPendingState(pendingOps); +} + +export function popPendingState(obj) { + let pendingOps = initializeState(obj).pendingOps; + return ObjectStateMutations.popPendingState(pendingOps); +} + +export function mergeFirstPendingState(obj) { + let pendingOps = getPendingOps(obj); + ObjectStateMutations.mergeFirstPendingState(pendingOps); +} + +export function getObjectCache(obj) { + let state = getState(obj); + if (state) { + return state.objectCache; + } + return {}; +} + +export function estimateAttribute(obj, attr) { + let serverData = getServerData(obj); + let pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); +} + +export function estimateAttributes(obj) { + let serverData = getServerData(obj); + let pendingOps = getPendingOps(obj); + return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); +} + +export function commitServerChanges(obj, changes) { + let state = initializeState(obj); + ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); +} + +export function enqueueTask(obj, task) { + let state = initializeState(obj); + return state.tasks.enqueue(task); +} + +export function duplicateState(source, dest) { + let oldState = initializeState(source); + let newState = initializeState(dest); + for (let key in oldState.serverData) { + newState.serverData[key] = oldState.serverData[key]; + } + for (let index = 0; index < oldState.pendingOps.length; index++) { + for (let key in oldState.pendingOps[index]) { + newState.pendingOps[index][key] = oldState.pendingOps[index][key]; + } + } + for (let key in oldState.objectCache) { + newState.objectCache[key] = oldState.objectCache[key]; + } + newState.existed = oldState.existed; +} + +export function clearAllState() { + objectState = new WeakMap(); +} \ No newline at end of file diff --git a/lib/react-native/arrayContainsObject.js b/lib/react-native/arrayContainsObject.js new file mode 100644 index 000000000..153c7320b --- /dev/null +++ b/lib/react-native/arrayContainsObject.js @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseObject from './ParseObject'; + +export default function arrayContainsObject(array, object) { + if (array.indexOf(object) > -1) { + return true; + } + for (var i = 0; i < array.length; i++) { + if (array[i] instanceof ParseObject && array[i].className === object.className && array[i]._getId() === object._getId()) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/lib/react-native/canBeSerialized.js b/lib/react-native/canBeSerialized.js new file mode 100644 index 000000000..b696d8028 --- /dev/null +++ b/lib/react-native/canBeSerialized.js @@ -0,0 +1,60 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseFile from './ParseFile'; +import ParseObject from './ParseObject'; +import ParseRelation from './ParseRelation'; + +export default function canBeSerialized(obj) { + if (!(obj instanceof ParseObject)) { + return true; + } + var attributes = obj.attributes; + for (var attr in attributes) { + var val = attributes[attr]; + if (!canBeSerializedHelper(val)) { + return false; + } + } + return true; +} + +function canBeSerializedHelper(value) { + if (typeof value !== 'object') { + return true; + } + if (value instanceof ParseRelation) { + return true; + } + if (value instanceof ParseObject) { + return !!value.id; + } + if (value instanceof ParseFile) { + if (value.url()) { + return true; + } + return false; + } + if (Array.isArray(value)) { + for (var i = 0; i < value.length; i++) { + if (!canBeSerializedHelper(value[i])) { + return false; + } + } + return true; + } + for (var k in value) { + if (!canBeSerializedHelper(value[k])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/react-native/decode.js b/lib/react-native/decode.js new file mode 100644 index 000000000..9863da760 --- /dev/null +++ b/lib/react-native/decode.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseACL from './ParseACL'; +import ParseFile from './ParseFile'; +import ParseGeoPoint from './ParseGeoPoint'; +import ParseObject from './ParseObject'; +import { opFromJSON } from './ParseOp'; +import ParseRelation from './ParseRelation'; + +export default function decode(value) { + if (value === null || typeof value !== 'object') { + return value; + } + if (Array.isArray(value)) { + var dup = []; + value.forEach((v, i) => { + dup[i] = decode(v); + }); + return dup; + } + if (typeof value.__op === 'string') { + return opFromJSON(value); + } + if (value.__type === 'Pointer' && value.className) { + return ParseObject.fromJSON(value); + } + if (value.__type === 'Object' && value.className) { + return ParseObject.fromJSON(value); + } + if (value.__type === 'Relation') { + // The parent and key fields will be populated by the parent + var relation = new ParseRelation(null, null); + relation.targetClassName = value.className; + return relation; + } + if (value.__type === 'Date') { + return new Date(value.iso); + } + if (value.__type === 'File') { + return ParseFile.fromJSON(value); + } + if (value.__type === 'GeoPoint') { + return new ParseGeoPoint({ + latitude: value.latitude, + longitude: value.longitude + }); + } + var copy = {}; + for (var k in value) { + copy[k] = decode(value[k]); + } + return copy; +} \ No newline at end of file diff --git a/lib/react-native/encode.js b/lib/react-native/encode.js new file mode 100644 index 000000000..74a925352 --- /dev/null +++ b/lib/react-native/encode.js @@ -0,0 +1,71 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseACL from './ParseACL'; +import ParseFile from './ParseFile'; +import ParseGeoPoint from './ParseGeoPoint'; +import ParseObject from './ParseObject'; +import { Op } from './ParseOp'; +import ParseRelation from './ParseRelation'; + +var toString = Object.prototype.toString; + +function encode(value, disallowObjects, forcePointers, seen) { + if (value instanceof ParseObject) { + if (disallowObjects) { + throw new Error('Parse Objects not allowed here'); + } + var seenEntry = value.id ? value.className + ':' + value.id : value; + if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || Object.keys(value._getServerData()).length < 1) { + return value.toPointer(); + } + seen = seen.concat(seenEntry); + return value._toFullJSON(seen); + } + if (value instanceof Op || value instanceof ParseACL || value instanceof ParseGeoPoint || value instanceof ParseRelation) { + return value.toJSON(); + } + if (value instanceof ParseFile) { + if (!value.url()) { + throw new Error('Tried to encode an unsaved file.'); + } + return value.toJSON(); + } + if (toString.call(value) === '[object Date]') { + if (isNaN(value)) { + throw new Error('Tried to encode an invalid date.'); + } + return { __type: 'Date', iso: value.toJSON() }; + } + if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { + return value.source; + } + + if (Array.isArray(value)) { + return value.map(v => { + return encode(v, disallowObjects, forcePointers, seen); + }); + } + + if (value && typeof value === 'object') { + var output = {}; + for (var k in value) { + output[k] = encode(value[k], disallowObjects, forcePointers, seen); + } + return output; + } + + return value; +} + +export default function (value, disallowObjects, forcePointers, seen) { + return encode(value, !!disallowObjects, !!forcePointers, seen || []); +} \ No newline at end of file diff --git a/lib/react-native/equals.js b/lib/react-native/equals.js new file mode 100644 index 000000000..06ff31f3c --- /dev/null +++ b/lib/react-native/equals.js @@ -0,0 +1,53 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +import ParseACL from './ParseACL'; +import ParseFile from './ParseFile'; +import ParseGeoPoint from './ParseGeoPoint'; +import ParseObject from './ParseObject'; + +export default function equals(a, b) { + if (typeof a !== typeof b) { + return false; + } + + if (!a || typeof a !== 'object') { + // a is a primitive + return a === b; + } + + if (Array.isArray(a) || Array.isArray(b)) { + if (!Array.isArray(a) || !Array.isArray(b)) { + return false; + } + if (a.length !== b.length) { + return false; + } + for (var i = a.length; i--;) { + if (!equals(a[i], b[i])) { + return false; + } + } + return true; + } + + if (a instanceof ParseACL || a instanceof ParseFile || a instanceof ParseGeoPoint || a instanceof ParseObject) { + return a.equals(b); + } + + if (Object.keys(a).length !== Object.keys(b).length) { + return false; + } + for (var k in a) { + if (!equals(a[k], b[k])) { + return false; + } + } + return true; +} \ No newline at end of file diff --git a/lib/react-native/escape.js b/lib/react-native/escape.js new file mode 100644 index 000000000..e094f0747 --- /dev/null +++ b/lib/react-native/escape.js @@ -0,0 +1,25 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +var encoded = { + '&': '&', + '<': '<', + '>': '>', + '/': '/', + '\'': ''', + '"': '"' +}; + +export default function escape(str) { + return str.replace(/[&<>\/'"]/g, function (char) { + return encoded[char]; + }); +} \ No newline at end of file diff --git a/lib/react-native/isRevocableSession.js b/lib/react-native/isRevocableSession.js new file mode 100644 index 000000000..967341a57 --- /dev/null +++ b/lib/react-native/isRevocableSession.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +export default function isRevocableSession(token) { + return token.indexOf('r:') > -1; +} \ No newline at end of file diff --git a/lib/react-native/parseDate.js b/lib/react-native/parseDate.js new file mode 100644 index 000000000..fe7538e41 --- /dev/null +++ b/lib/react-native/parseDate.js @@ -0,0 +1,28 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +export default function parseDate(iso8601) { + var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); + var match = regexp.exec(iso8601); + if (!match) { + return null; + } + + var year = match[1] || 0; + var month = (match[2] || 1) - 1; + var day = match[3] || 0; + var hour = match[4] || 0; + var minute = match[5] || 0; + var second = match[6] || 0; + var milli = match[8] || 0; + + return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); +} \ No newline at end of file diff --git a/lib/react-native/unique.js b/lib/react-native/unique.js new file mode 100644 index 000000000..c3d1e6364 --- /dev/null +++ b/lib/react-native/unique.js @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import arrayContainsObject from './arrayContainsObject'; +import ParseObject from './ParseObject'; + +export default function unique(arr) { + var uniques = []; + arr.forEach(value => { + if (value instanceof ParseObject) { + if (!arrayContainsObject(uniques, value)) { + uniques.push(value); + } + } else { + if (uniques.indexOf(value) < 0) { + uniques.push(value); + } + } + }); + return uniques; +} \ No newline at end of file diff --git a/lib/react-native/unsavedChildren.js b/lib/react-native/unsavedChildren.js new file mode 100644 index 000000000..5b71deea0 --- /dev/null +++ b/lib/react-native/unsavedChildren.js @@ -0,0 +1,80 @@ +/** + * Copyright (c) 2015-present, Parse, LLC. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * + */ + +import ParseFile from './ParseFile'; +import ParseObject from './ParseObject'; +import ParseRelation from './ParseRelation'; + +/** + * Return an array of unsaved children, which are either Parse Objects or Files. + * If it encounters any dirty Objects without Ids, it will throw an exception. + */ +export default function unsavedChildren(obj, allowDeepUnsaved) { + var encountered = { + objects: {}, + files: [] + }; + var identifier = obj.className + ':' + obj._getId(); + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if (typeof attributes[attr] === 'object') { + traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); + } + } + var unsaved = []; + for (var id in encountered.objects) { + if (id !== identifier && encountered.objects[id] !== true) { + unsaved.push(encountered.objects[id]); + } + } + return unsaved.concat(encountered.files); +} + +function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { + if (obj instanceof ParseObject) { + if (!obj.id && shouldThrow) { + throw new Error('Cannot create a pointer to an unsaved Object.'); + } + var identifier = obj.className + ':' + obj._getId(); + if (!encountered.objects[identifier]) { + encountered.objects[identifier] = obj.dirty() ? obj : true; + var attributes = obj.attributes; + for (var attr in attributes) { + if (typeof attributes[attr] === 'object') { + traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); + } + } + } + return; + } + if (obj instanceof ParseFile) { + if (!obj.url() && encountered.files.indexOf(obj) < 0) { + encountered.files.push(obj); + } + return; + } + if (obj instanceof ParseRelation) { + return; + } + if (Array.isArray(obj)) { + obj.forEach(el => { + if (typeof el === 'object') { + traverse(el, encountered, shouldThrow, allowDeepUnsaved); + } + }); + } + for (var k in obj) { + if (typeof obj[k] === 'object') { + traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); + } + } +} \ No newline at end of file From 9393e0cf00225381e6ee1b769d62c5ec84b436f2 Mon Sep 17 00:00:00 2001 From: Eduard Bosch Bertran Date: Fri, 26 May 2017 08:57:34 +0200 Subject: [PATCH 3/3] Revert "feat: Include dist & lib folders" This reverts commit 4494b86375277686f69b6086e132420a578b7c89. --- .gitignore | 4 +- dist/parse.js | 13937 ---------------- dist/parse.min.js | 18 - lib/browser/Analytics.js | 89 - lib/browser/Cloud.js | 109 - lib/browser/CoreManager.js | 161 - lib/browser/EventEmitter.js | 15 - lib/browser/FacebookUtils.js | 243 - lib/browser/InstallationController.js | 64 - lib/browser/LiveQueryClient.js | 595 - lib/browser/LiveQuerySubscription.js | 162 - lib/browser/ObjectStateMutations.js | 165 - lib/browser/Parse.js | 186 - lib/browser/ParseACL.js | 406 - lib/browser/ParseConfig.js | 228 - lib/browser/ParseError.js | 507 - lib/browser/ParseFile.js | 291 - lib/browser/ParseGeoPoint.js | 235 - lib/browser/ParseHooks.js | 162 - lib/browser/ParseInstallation.js | 65 - lib/browser/ParseLiveQuery.js | 241 - lib/browser/ParseObject.js | 2001 --- lib/browser/ParseOp.js | 579 - lib/browser/ParsePromise.js | 740 - lib/browser/ParseQuery.js | 1340 -- lib/browser/ParseRelation.js | 182 - lib/browser/ParseRole.js | 196 - lib/browser/ParseSession.js | 180 - lib/browser/ParseUser.js | 1150 -- lib/browser/Push.js | 98 - lib/browser/RESTController.js | 248 - lib/browser/SingleInstanceStateController.js | 160 - lib/browser/Storage.js | 93 - lib/browser/StorageController.browser.js | 41 - lib/browser/StorageController.default.js | 41 - lib/browser/StorageController.react-native.js | 67 - lib/browser/TaskQueue.js | 77 - lib/browser/UniqueInstanceStateController.js | 189 - lib/browser/arrayContainsObject.js | 35 - lib/browser/canBeSerialized.js | 82 - lib/browser/decode.js | 93 - lib/browser/encode.js | 104 - lib/browser/equals.js | 84 - lib/browser/escape.js | 31 - lib/browser/isRevocableSession.js | 20 - lib/browser/parseDate.js | 34 - lib/browser/unique.js | 45 - lib/browser/unsavedChildren.js | 102 - lib/node/Analytics.js | 89 - lib/node/Cloud.js | 109 - lib/node/CoreManager.js | 161 - lib/node/EventEmitter.js | 15 - lib/node/FacebookUtils.js | 243 - lib/node/InstallationController.js | 64 - lib/node/LiveQueryClient.js | 595 - lib/node/LiveQuerySubscription.js | 162 - lib/node/ObjectStateMutations.js | 165 - lib/node/Parse.js | 190 - lib/node/ParseACL.js | 406 - lib/node/ParseConfig.js | 228 - lib/node/ParseError.js | 507 - lib/node/ParseFile.js | 291 - lib/node/ParseGeoPoint.js | 235 - lib/node/ParseHooks.js | 162 - lib/node/ParseInstallation.js | 65 - lib/node/ParseLiveQuery.js | 241 - lib/node/ParseObject.js | 2001 --- lib/node/ParseOp.js | 579 - lib/node/ParsePromise.js | 740 - lib/node/ParseQuery.js | 1340 -- lib/node/ParseRelation.js | 182 - lib/node/ParseRole.js | 196 - lib/node/ParseSession.js | 180 - lib/node/ParseUser.js | 1150 -- lib/node/Push.js | 98 - lib/node/RESTController.js | 250 - lib/node/SingleInstanceStateController.js | 160 - lib/node/Storage.js | 93 - lib/node/StorageController.browser.js | 41 - lib/node/StorageController.default.js | 41 - lib/node/StorageController.react-native.js | 67 - lib/node/TaskQueue.js | 77 - lib/node/UniqueInstanceStateController.js | 189 - lib/node/arrayContainsObject.js | 35 - lib/node/canBeSerialized.js | 82 - lib/node/decode.js | 93 - lib/node/encode.js | 104 - lib/node/equals.js | 84 - lib/node/escape.js | 31 - lib/node/isRevocableSession.js | 20 - lib/node/parseDate.js | 34 - lib/node/unique.js | 45 - lib/node/unsavedChildren.js | 102 - lib/react-native/Analytics.js | 78 - lib/react-native/Cloud.js | 86 - lib/react-native/CoreManager.js | 188 - lib/react-native/EventEmitter.js | 16 - lib/react-native/FacebookUtils.js | 229 - lib/react-native/InstallationController.js | 54 - lib/react-native/LiveQueryClient.js | 430 - lib/react-native/LiveQuerySubscription.js | 112 - lib/react-native/ObjectStateMutations.js | 121 - lib/react-native/Parse.js | 141 - lib/react-native/ParseACL.js | 325 - lib/react-native/ParseConfig.js | 168 - lib/react-native/ParseError.js | 491 - lib/react-native/ParseFile.js | 247 - lib/react-native/ParseGeoPoint.js | 186 - lib/react-native/ParseHooks.js | 125 - lib/react-native/ParseInstallation.js | 25 - lib/react-native/ParseLiveQuery.js | 212 - lib/react-native/ParseObject.js | 1742 -- lib/react-native/ParseOp.js | 434 - lib/react-native/ParsePromise.js | 575 - lib/react-native/ParseQuery.js | 1113 -- lib/react-native/ParseRelation.js | 140 - lib/react-native/ParseRole.js | 133 - lib/react-native/ParseSession.js | 114 - lib/react-native/ParseUser.js | 952 -- lib/react-native/Push.js | 77 - lib/react-native/RESTController.js | 226 - .../SingleInstanceStateController.js | 125 - lib/react-native/Storage.js | 92 - lib/react-native/StorageController.browser.js | 38 - lib/react-native/StorageController.default.js | 41 - .../StorageController.react-native.js | 60 - lib/react-native/TaskQueue.js | 53 - .../UniqueInstanceStateController.js | 140 - lib/react-native/arrayContainsObject.js | 24 - lib/react-native/canBeSerialized.js | 60 - lib/react-native/decode.js | 62 - lib/react-native/encode.js | 71 - lib/react-native/equals.js | 53 - lib/react-native/escape.js | 25 - lib/react-native/isRevocableSession.js | 14 - lib/react-native/parseDate.js | 28 - lib/react-native/unique.js | 29 - lib/react-native/unsavedChildren.js | 80 - 138 files changed, 2 insertions(+), 47570 deletions(-) delete mode 100644 dist/parse.js delete mode 100644 dist/parse.min.js delete mode 100644 lib/browser/Analytics.js delete mode 100644 lib/browser/Cloud.js delete mode 100644 lib/browser/CoreManager.js delete mode 100644 lib/browser/EventEmitter.js delete mode 100644 lib/browser/FacebookUtils.js delete mode 100644 lib/browser/InstallationController.js delete mode 100644 lib/browser/LiveQueryClient.js delete mode 100644 lib/browser/LiveQuerySubscription.js delete mode 100644 lib/browser/ObjectStateMutations.js delete mode 100644 lib/browser/Parse.js delete mode 100644 lib/browser/ParseACL.js delete mode 100644 lib/browser/ParseConfig.js delete mode 100644 lib/browser/ParseError.js delete mode 100644 lib/browser/ParseFile.js delete mode 100644 lib/browser/ParseGeoPoint.js delete mode 100644 lib/browser/ParseHooks.js delete mode 100644 lib/browser/ParseInstallation.js delete mode 100644 lib/browser/ParseLiveQuery.js delete mode 100644 lib/browser/ParseObject.js delete mode 100644 lib/browser/ParseOp.js delete mode 100644 lib/browser/ParsePromise.js delete mode 100644 lib/browser/ParseQuery.js delete mode 100644 lib/browser/ParseRelation.js delete mode 100644 lib/browser/ParseRole.js delete mode 100644 lib/browser/ParseSession.js delete mode 100644 lib/browser/ParseUser.js delete mode 100644 lib/browser/Push.js delete mode 100644 lib/browser/RESTController.js delete mode 100644 lib/browser/SingleInstanceStateController.js delete mode 100644 lib/browser/Storage.js delete mode 100644 lib/browser/StorageController.browser.js delete mode 100644 lib/browser/StorageController.default.js delete mode 100644 lib/browser/StorageController.react-native.js delete mode 100644 lib/browser/TaskQueue.js delete mode 100644 lib/browser/UniqueInstanceStateController.js delete mode 100644 lib/browser/arrayContainsObject.js delete mode 100644 lib/browser/canBeSerialized.js delete mode 100644 lib/browser/decode.js delete mode 100644 lib/browser/encode.js delete mode 100644 lib/browser/equals.js delete mode 100644 lib/browser/escape.js delete mode 100644 lib/browser/isRevocableSession.js delete mode 100644 lib/browser/parseDate.js delete mode 100644 lib/browser/unique.js delete mode 100644 lib/browser/unsavedChildren.js delete mode 100644 lib/node/Analytics.js delete mode 100644 lib/node/Cloud.js delete mode 100644 lib/node/CoreManager.js delete mode 100644 lib/node/EventEmitter.js delete mode 100644 lib/node/FacebookUtils.js delete mode 100644 lib/node/InstallationController.js delete mode 100644 lib/node/LiveQueryClient.js delete mode 100644 lib/node/LiveQuerySubscription.js delete mode 100644 lib/node/ObjectStateMutations.js delete mode 100644 lib/node/Parse.js delete mode 100644 lib/node/ParseACL.js delete mode 100644 lib/node/ParseConfig.js delete mode 100644 lib/node/ParseError.js delete mode 100644 lib/node/ParseFile.js delete mode 100644 lib/node/ParseGeoPoint.js delete mode 100644 lib/node/ParseHooks.js delete mode 100644 lib/node/ParseInstallation.js delete mode 100644 lib/node/ParseLiveQuery.js delete mode 100644 lib/node/ParseObject.js delete mode 100644 lib/node/ParseOp.js delete mode 100644 lib/node/ParsePromise.js delete mode 100644 lib/node/ParseQuery.js delete mode 100644 lib/node/ParseRelation.js delete mode 100644 lib/node/ParseRole.js delete mode 100644 lib/node/ParseSession.js delete mode 100644 lib/node/ParseUser.js delete mode 100644 lib/node/Push.js delete mode 100644 lib/node/RESTController.js delete mode 100644 lib/node/SingleInstanceStateController.js delete mode 100644 lib/node/Storage.js delete mode 100644 lib/node/StorageController.browser.js delete mode 100644 lib/node/StorageController.default.js delete mode 100644 lib/node/StorageController.react-native.js delete mode 100644 lib/node/TaskQueue.js delete mode 100644 lib/node/UniqueInstanceStateController.js delete mode 100644 lib/node/arrayContainsObject.js delete mode 100644 lib/node/canBeSerialized.js delete mode 100644 lib/node/decode.js delete mode 100644 lib/node/encode.js delete mode 100644 lib/node/equals.js delete mode 100644 lib/node/escape.js delete mode 100644 lib/node/isRevocableSession.js delete mode 100644 lib/node/parseDate.js delete mode 100644 lib/node/unique.js delete mode 100644 lib/node/unsavedChildren.js delete mode 100644 lib/react-native/Analytics.js delete mode 100644 lib/react-native/Cloud.js delete mode 100644 lib/react-native/CoreManager.js delete mode 100644 lib/react-native/EventEmitter.js delete mode 100644 lib/react-native/FacebookUtils.js delete mode 100644 lib/react-native/InstallationController.js delete mode 100644 lib/react-native/LiveQueryClient.js delete mode 100644 lib/react-native/LiveQuerySubscription.js delete mode 100644 lib/react-native/ObjectStateMutations.js delete mode 100644 lib/react-native/Parse.js delete mode 100644 lib/react-native/ParseACL.js delete mode 100644 lib/react-native/ParseConfig.js delete mode 100644 lib/react-native/ParseError.js delete mode 100644 lib/react-native/ParseFile.js delete mode 100644 lib/react-native/ParseGeoPoint.js delete mode 100644 lib/react-native/ParseHooks.js delete mode 100644 lib/react-native/ParseInstallation.js delete mode 100644 lib/react-native/ParseLiveQuery.js delete mode 100644 lib/react-native/ParseObject.js delete mode 100644 lib/react-native/ParseOp.js delete mode 100644 lib/react-native/ParsePromise.js delete mode 100644 lib/react-native/ParseQuery.js delete mode 100644 lib/react-native/ParseRelation.js delete mode 100644 lib/react-native/ParseRole.js delete mode 100644 lib/react-native/ParseSession.js delete mode 100644 lib/react-native/ParseUser.js delete mode 100644 lib/react-native/Push.js delete mode 100644 lib/react-native/RESTController.js delete mode 100644 lib/react-native/SingleInstanceStateController.js delete mode 100644 lib/react-native/Storage.js delete mode 100644 lib/react-native/StorageController.browser.js delete mode 100644 lib/react-native/StorageController.default.js delete mode 100644 lib/react-native/StorageController.react-native.js delete mode 100644 lib/react-native/TaskQueue.js delete mode 100644 lib/react-native/UniqueInstanceStateController.js delete mode 100644 lib/react-native/arrayContainsObject.js delete mode 100644 lib/react-native/canBeSerialized.js delete mode 100644 lib/react-native/decode.js delete mode 100644 lib/react-native/encode.js delete mode 100644 lib/react-native/equals.js delete mode 100644 lib/react-native/escape.js delete mode 100644 lib/react-native/isRevocableSession.js delete mode 100644 lib/react-native/parseDate.js delete mode 100644 lib/react-native/unique.js delete mode 100644 lib/react-native/unsavedChildren.js diff --git a/.gitignore b/.gitignore index 16a5fb13e..fcef25c5e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ coverage -#dist -#lib +dist +lib logs node_modules test_output diff --git a/dist/parse.js b/dist/parse.js deleted file mode 100644 index 1e049cfeb..000000000 --- a/dist/parse.js +++ /dev/null @@ -1,13937 +0,0 @@ -/** - * Parse JavaScript SDK v1.9.2 - * - * The source tree of this library can be found at - * https://github.com/ParsePlatform/Parse-SDK-JS - */ -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Parse = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o - * var dimensions = { - * gender: 'm', - * source: 'web', - * dayType: 'weekend' - * }; - * Parse.Analytics.track('signup', dimensions); - * - * - * There is a default limit of 8 dimensions per event tracked. - * - * @method track - * @param {String} name The name of the custom event to report to Parse as - * having happened. - * @param {Object} dimensions The dictionary of information by which to - * segment this event. - * @param {Object} options A Backbone-style callback object. - * @return {Parse.Promise} A promise that is resolved when the round-trip - * to the server completes. - */ -function track(name, dimensions, options) { - name = name || ''; - name = name.replace(/^\s*/, ''); - name = name.replace(/\s*$/, ''); - if (name.length === 0) { - throw new TypeError('A name for the custom event must be provided'); - } - - for (var key in dimensions) { - if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { - throw new TypeError('track() dimensions expects keys and values of type "string".'); - } - } - - options = options || {}; - return _CoreManager2.default.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var DefaultController = { - track: function (name, dimensions) { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); - } -}; - -_CoreManager2.default.setAnalyticsController(DefaultController); -},{"./CoreManager":3}],2:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.run = run; - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = _dereq_('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains functions for calling and declaring - * cloud functions. - *

                  - * Some functions are only available from Cloud Code. - *

                  - * - * @class Parse.Cloud - * @static - */ - -/** - * Makes a call to a cloud function. - * @method run - * @param {String} name The function name. - * @param {Object} data The parameters to send to the cloud function. - * @param {Object} options A Backbone-style options object - * options.success, if set, should be a function to handle a successful - * call to a cloud function. options.error should be a function that - * handles an error running the cloud function. Both functions are - * optional. Both functions take a single argument. - * @return {Parse.Promise} A promise that will be resolved with the result - * of the function. - */ -function run(name, data, options) { - options = options || {}; - - if (typeof name !== 'string' || name.length === 0) { - throw new TypeError('Cloud function name must be a string.'); - } - - var requestOptions = {}; - if (options.useMasterKey) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.sessionToken) { - requestOptions.sessionToken = options.sessionToken; - } - - return _CoreManager2.default.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var DefaultController = { - run: function (name, data, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - var payload = (0, _encode2.default)(data, true); - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - requestOptions.sessionToken = options.sessionToken; - } - - var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); - - return request.then(function (res) { - var decoded = (0, _decode2.default)(res); - if (decoded && decoded.hasOwnProperty('result')) { - return _ParsePromise2.default.as(decoded.result); - } - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); - })._thenRunCallbacks(options); - } -}; - -_CoreManager2.default.setCloudController(DefaultController); -},{"./CoreManager":3,"./ParseError":13,"./ParsePromise":20,"./decode":35,"./encode":36}],3:[function(_dereq_,module,exports){ -(function (process){ -'use strict'; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var config = { - // Defaults - IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, - REQUEST_ATTEMPT_LIMIT: 5, - SERVER_URL: 'https://api.parse.com/1', - LIVEQUERY_SERVER_URL: null, - VERSION: 'js' + '1.9.2', - APPLICATION_ID: null, - JAVASCRIPT_KEY: null, - MASTER_KEY: null, - USE_MASTER_KEY: false, - PERFORM_USER_REWRITE: true, - FORCE_REVOCABLE_SESSION: false -}; - -function requireMethods(name, methods, controller) { - methods.forEach(function (func) { - if (typeof controller[func] !== 'function') { - throw new Error(name + ' must implement ' + func + '()'); - } - }); -} - -module.exports = { - get: function (key) { - if (config.hasOwnProperty(key)) { - return config[key]; - } - throw new Error('Configuration key not found: ' + key); - }, - - set: function (key, value) { - config[key] = value; - }, - - /* Specialized Controller Setters/Getters */ - - setAnalyticsController: function (controller) { - requireMethods('AnalyticsController', ['track'], controller); - config['AnalyticsController'] = controller; - }, - getAnalyticsController: function () { - return config['AnalyticsController']; - }, - setCloudController: function (controller) { - requireMethods('CloudController', ['run'], controller); - config['CloudController'] = controller; - }, - getCloudController: function () { - return config['CloudController']; - }, - setConfigController: function (controller) { - requireMethods('ConfigController', ['current', 'get'], controller); - config['ConfigController'] = controller; - }, - getConfigController: function () { - return config['ConfigController']; - }, - setFileController: function (controller) { - requireMethods('FileController', ['saveFile', 'saveBase64'], controller); - config['FileController'] = controller; - }, - getFileController: function () { - return config['FileController']; - }, - setInstallationController: function (controller) { - requireMethods('InstallationController', ['currentInstallationId'], controller); - config['InstallationController'] = controller; - }, - getInstallationController: function () { - return config['InstallationController']; - }, - setObjectController: function (controller) { - requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); - config['ObjectController'] = controller; - }, - getObjectController: function () { - return config['ObjectController']; - }, - setObjectStateController: function (controller) { - requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); - - config['ObjectStateController'] = controller; - }, - getObjectStateController: function () { - return config['ObjectStateController']; - }, - setPushController: function (controller) { - requireMethods('PushController', ['send'], controller); - config['PushController'] = controller; - }, - getPushController: function () { - return config['PushController']; - }, - setQueryController: function (controller) { - requireMethods('QueryController', ['find'], controller); - config['QueryController'] = controller; - }, - getQueryController: function () { - return config['QueryController']; - }, - setRESTController: function (controller) { - requireMethods('RESTController', ['request', 'ajax'], controller); - config['RESTController'] = controller; - }, - getRESTController: function () { - return config['RESTController']; - }, - setSessionController: function (controller) { - requireMethods('SessionController', ['getSession'], controller); - config['SessionController'] = controller; - }, - getSessionController: function () { - return config['SessionController']; - }, - setStorageController: function (controller) { - if (controller.async) { - requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); - } else { - requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); - } - config['StorageController'] = controller; - }, - getStorageController: function () { - return config['StorageController']; - }, - setUserController: function (controller) { - requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); - config['UserController'] = controller; - }, - getUserController: function () { - return config['UserController']; - }, - setLiveQueryController: function (controller) { - requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); - config['LiveQueryController'] = controller; - }, - getLiveQueryController: function () { - return config['LiveQueryController']; - }, - setHooksController: function (controller) { - requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); - config['HooksController'] = controller; - }, - getHooksController: function () { - return config['HooksController']; - } -}; -}).call(this,_dereq_('_process')) -},{"_process":168}],4:[function(_dereq_,module,exports){ -'use strict'; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This is a simple wrapper to unify EventEmitter implementations across platforms. - */ - -module.exports = _dereq_('events').EventEmitter; -var EventEmitter; -},{"events":169}],5:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _parseDate = _dereq_('./parseDate'); - -var _parseDate2 = _interopRequireDefault(_parseDate); - -var _ParseUser = _dereq_('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * -weak - */ - -var PUBLIC_KEY = "*"; - -var initialized = false; -var requestedPermissions; -var initOptions; -var provider = { - authenticate: function (options) { - var _this = this; - - if (typeof FB === 'undefined') { - options.error(this, 'Facebook SDK not found.'); - } - FB.login(function (response) { - if (response.authResponse) { - if (options.success) { - options.success(_this, { - id: response.authResponse.userID, - access_token: response.authResponse.accessToken, - expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() - }); - } - } else { - if (options.error) { - options.error(_this, response); - } - } - }, { - scope: requestedPermissions - }); - }, - restoreAuthentication: function (authData) { - if (authData) { - var expiration = (0, _parseDate2.default)(authData.expiration_date); - var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; - - var authResponse = { - userID: authData.id, - accessToken: authData.access_token, - expiresIn: expiresIn - }; - var newOptions = {}; - if (initOptions) { - for (var key in initOptions) { - newOptions[key] = initOptions[key]; - } - } - newOptions.authResponse = authResponse; - - // Suppress checks for login status from the browser. - newOptions.status = false; - - // If the user doesn't match the one known by the FB SDK, log out. - // Most of the time, the users will match -- it's only in cases where - // the FB SDK knows of a different user than the one being restored - // from a Parse User that logged in with username/password. - var existingResponse = FB.getAuthResponse(); - if (existingResponse && existingResponse.userID !== authResponse.userID) { - FB.logout(); - } - - FB.init(newOptions); - } - return true; - }, - getAuthType: function () { - return 'facebook'; - }, - deauthenticate: function () { - this.restoreAuthentication(null); - } -}; - -/** - * Provides a set of utilities for using Parse with Facebook. - * @class Parse.FacebookUtils - * @static - */ -var FacebookUtils = { - /** - * Initializes Parse Facebook integration. Call this function after you - * have loaded the Facebook Javascript SDK with the same parameters - * as you would pass to - * - * FB.init(). Parse.FacebookUtils will invoke FB.init() for you - * with these arguments. - * - * @method init - * @param {Object} options Facebook options argument as described here: - * - * FB.init(). The status flag will be coerced to 'false' because it - * interferes with Parse Facebook integration. Call FB.getLoginStatus() - * explicitly if this behavior is required by your application. - */ - init: function (options) { - if (typeof FB === 'undefined') { - throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); - } - initOptions = {}; - if (options) { - for (var key in options) { - initOptions[key] = options[key]; - } - } - if (initOptions.status && typeof console !== 'undefined') { - var warn = console.warn || console.log || function () {}; - warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); - } - initOptions.status = false; - FB.init(initOptions); - _ParseUser2.default._registerAuthenticationProvider(provider); - initialized = true; - }, - - /** - * Gets whether the user has their account linked to Facebook. - * - * @method isLinked - * @param {Parse.User} user User to check for a facebook link. - * The user must be logged in on this device. - * @return {Boolean} true if the user has their account - * linked to Facebook. - */ - isLinked: function (user) { - return user._isLinked('facebook'); - }, - - /** - * Logs in a user using Facebook. This method delegates to the Facebook - * SDK to authenticate the user, and then automatically logs in (or - * creates, in the case where it is a new user) a Parse.User. - * - * @method logIn - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - logIn: function (permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling logIn.'); - } - requestedPermissions = permissions; - return _ParseUser2.default._logInWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return _ParseUser2.default._logInWith('facebook', newOptions); - } - }, - - /** - * Links Facebook to an existing PFUser. This method delegates to the - * Facebook SDK to authenticate the user, and then automatically links - * the account to the Parse.User. - * - * @method link - * @param {Parse.User} user User to link to Facebook. This must be the - * current user. - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - link: function (user, permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling link.'); - } - requestedPermissions = permissions; - return user._linkWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return user._linkWith('facebook', newOptions); - } - }, - - /** - * Unlinks the Parse.User from a Facebook account. - * - * @method unlink - * @param {Parse.User} user User to unlink from Facebook. This must be the - * current user. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - unlink: function (user, options) { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling unlink.'); - } - return user._unlinkFrom('facebook', options); - } -}; - -exports.default = FacebookUtils; -},{"./ParseUser":25,"./parseDate":40}],6:[function(_dereq_,module,exports){ -'use strict'; - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = _dereq_('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var iidCache = null; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function hexOctet() { - return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); -} - -function generateId() { - return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); -} - -var InstallationController = { - currentInstallationId: function () { - if (typeof iidCache === 'string') { - return _ParsePromise2.default.as(iidCache); - } - var path = _Storage2.default.generatePath('installationId'); - return _Storage2.default.getItemAsync(path).then(function (iid) { - if (!iid) { - iid = generateId(); - return _Storage2.default.setItemAsync(path, iid).then(function () { - iidCache = iid; - return iid; - }); - } - iidCache = iid; - return iid; - }); - }, - _clearCache: function () { - iidCache = null; - }, - _setInstallationIdCache: function (iid) { - iidCache = iid; - } -}; - -module.exports = InstallationController; -},{"./CoreManager":3,"./ParsePromise":20,"./Storage":29}],7:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getIterator2 = _dereq_('babel-runtime/core-js/get-iterator'); - -var _getIterator3 = _interopRequireDefault(_getIterator2); - -var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _map = _dereq_('babel-runtime/core-js/map'); - -var _map2 = _interopRequireDefault(_map); - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _EventEmitter2 = _dereq_('./EventEmitter'); - -var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _LiveQuerySubscription = _dereq_('./LiveQuerySubscription'); - -var _LiveQuerySubscription2 = _interopRequireDefault(_LiveQuerySubscription); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -// The LiveQuery client inner state -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -var CLIENT_STATE = { - INITIALIZED: 'initialized', - CONNECTING: 'connecting', - CONNECTED: 'connected', - CLOSED: 'closed', - RECONNECTING: 'reconnecting', - DISCONNECTED: 'disconnected' -}; - -// The event type the LiveQuery client should sent to server -var OP_TYPES = { - CONNECT: 'connect', - SUBSCRIBE: 'subscribe', - UNSUBSCRIBE: 'unsubscribe', - ERROR: 'error' -}; - -// The event we get back from LiveQuery server -var OP_EVENTS = { - CONNECTED: 'connected', - SUBSCRIBED: 'subscribed', - UNSUBSCRIBED: 'unsubscribed', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -// The event the LiveQuery client should emit -var CLIENT_EMMITER_TYPES = { - CLOSE: 'close', - ERROR: 'error', - OPEN: 'open' -}; - -// The event the LiveQuery subscription should emit -var SUBSCRIPTION_EMMITER_TYPES = { - OPEN: 'open', - CLOSE: 'close', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -var generateInterval = function (k) { - return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; -}; - -/** - * Creates a new LiveQueryClient. - * Extends events.EventEmitter - * cloud functions. - * - * A wrapper of a standard WebSocket client. We add several useful methods to - * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. - * - * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries - * to connect to the LiveQuery server - * - * @class Parse.LiveQueryClient - * @constructor - * @param {Object} options - * @param {string} options.applicationId - applicationId of your Parse app - * @param {string} options.serverURL - the URL of your LiveQuery server - * @param {string} options.javascriptKey (optional) - * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) - * @param {string} options.sessionToken (optional) - * - * - * We expose three events to help you monitor the status of the LiveQueryClient. - * - *
                  - * let Parse = require('parse/node');
                  - * let LiveQueryClient = Parse.LiveQueryClient;
                  - * let client = new LiveQueryClient({
                  - *   applicationId: '',
                  - *   serverURL: '',
                  - *   javascriptKey: '',
                  - *   masterKey: ''
                  - *  });
                  - * 
                  - * - * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - *
                  - * client.on('open', () => {
                  - * 
                  - * });
                  - * - * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - *
                  - * client.on('close', () => {
                  - * 
                  - * });
                  - * - * Error - When some network error or LiveQuery server error happens, you'll get this event. - *
                  - * client.on('error', (error) => {
                  - * 
                  - * });
                  - * - * - */ - -var LiveQueryClient = function (_EventEmitter) { - (0, _inherits3.default)(LiveQueryClient, _EventEmitter); - - function LiveQueryClient(_ref) { - var applicationId = _ref.applicationId, - serverURL = _ref.serverURL, - javascriptKey = _ref.javascriptKey, - masterKey = _ref.masterKey, - sessionToken = _ref.sessionToken; - (0, _classCallCheck3.default)(this, LiveQueryClient); - - var _this = (0, _possibleConstructorReturn3.default)(this, (LiveQueryClient.__proto__ || (0, _getPrototypeOf2.default)(LiveQueryClient)).call(this)); - - if (!serverURL || serverURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - _this.reconnectHandle = null; - _this.attempts = 1;; - _this.id = 0; - _this.requestId = 1; - _this.serverURL = serverURL; - _this.applicationId = applicationId; - _this.javascriptKey = javascriptKey; - _this.masterKey = masterKey; - _this.sessionToken = sessionToken; - _this.connectPromise = new _ParsePromise2.default(); - _this.subscriptions = new _map2.default(); - _this.state = CLIENT_STATE.INITIALIZED; - return _this; - } - - (0, _createClass3.default)(LiveQueryClient, [{ - key: 'shouldOpen', - value: function () { - return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; - } - - /** - * Subscribes to a ParseQuery - * - * If you provide the sessionToken, when the LiveQuery server gets ParseObject's - * updates from parse server, it'll try to check whether the sessionToken fulfills - * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose - * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol - * here for more details. The subscription you get is the same subscription you get - * from our Standard API. - * - * @method subscribe - * @param {Object} query - the ParseQuery you want to subscribe to - * @param {string} sessionToken (optional) - * @return {Object} subscription - */ - - }, { - key: 'subscribe', - value: function (query, sessionToken) { - var _this2 = this; - - if (!query) { - return; - } - var where = query.toJSON().where; - var className = query.className; - var subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: this.requestId, - query: { - className: className, - where: where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - var subscription = new _LiveQuerySubscription2.default(this.requestId, query, sessionToken); - this.subscriptions.set(this.requestId, subscription); - this.requestId += 1; - this.connectPromise.then(function () { - _this2.socket.send((0, _stringify2.default)(subscribeRequest)); - }); - - // adding listener so process does not crash - // best practice is for developer to register their own listener - subscription.on('error', function () {}); - - return subscription; - } - - /** - * After calling unsubscribe you'll stop receiving events from the subscription object. - * - * @method unsubscribe - * @param {Object} subscription - subscription you would like to unsubscribe from. - */ - - }, { - key: 'unsubscribe', - value: function (subscription) { - var _this3 = this; - - if (!subscription) { - return; - } - - this.subscriptions.delete(subscription.id); - var unsubscribeRequest = { - op: OP_TYPES.UNSUBSCRIBE, - requestId: subscription.id - }; - this.connectPromise.then(function () { - _this3.socket.send((0, _stringify2.default)(unsubscribeRequest)); - }); - } - - /** - * After open is called, the LiveQueryClient will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ - - }, { - key: 'open', - value: function () { - var _this4 = this; - - var WebSocketImplementation = this._getWebSocketImplementation(); - if (!WebSocketImplementation) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); - return; - } - - if (this.state !== CLIENT_STATE.RECONNECTING) { - this.state = CLIENT_STATE.CONNECTING; - } - - // Get WebSocket implementation - this.socket = new WebSocketImplementation(this.serverURL); - - // Bind WebSocket callbacks - this.socket.onopen = function () { - _this4._handleWebSocketOpen(); - }; - - this.socket.onmessage = function (event) { - _this4._handleWebSocketMessage(event); - }; - - this.socket.onclose = function () { - _this4._handleWebSocketClose(); - }; - - this.socket.onerror = function (error) { - _this4._handleWebSocketError(error); - }; - } - }, { - key: 'resubscribe', - value: function () { - var _this5 = this; - - this.subscriptions.forEach(function (subscription, requestId) { - var query = subscription.query; - var where = query.toJSON().where; - var className = query.className; - var sessionToken = subscription.sessionToken; - var subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: requestId, - query: { - className: className, - where: where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - _this5.connectPromise.then(function () { - _this5.socket.send((0, _stringify2.default)(subscribeRequest)); - }); - }); - } - - /** - * This method will close the WebSocket connection to this LiveQueryClient, - * cancel the auto reconnect and unsubscribe all subscriptions based on it. - * - * @method close - */ - - }, { - key: 'close', - value: function () { - if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.DISCONNECTED; - this.socket.close(); - // Notify each subscription about the close - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = (0, _getIterator3.default)(this.subscriptions.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var subscription = _step.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - this._handleReset(); - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - } - }, { - key: '_getWebSocketImplementation', - value: function () { - return typeof WebSocket === 'function' || (typeof WebSocket === 'undefined' ? 'undefined' : (0, _typeof3.default)(WebSocket)) === 'object' ? WebSocket : null; - } - - // ensure we start with valid state if connect is called again after close - - }, { - key: '_handleReset', - value: function () { - this.attempts = 1;; - this.id = 0; - this.requestId = 1; - this.connectPromise = new _ParsePromise2.default(); - this.subscriptions = new _map2.default(); - } - }, { - key: '_handleWebSocketOpen', - value: function () { - this.attempts = 1; - var connectRequest = { - op: OP_TYPES.CONNECT, - applicationId: this.applicationId, - javascriptKey: this.javascriptKey, - masterKey: this.masterKey, - sessionToken: this.sessionToken - }; - this.socket.send((0, _stringify2.default)(connectRequest)); - } - }, { - key: '_handleWebSocketMessage', - value: function (event) { - var data = event.data; - if (typeof data === 'string') { - data = JSON.parse(data); - } - var subscription = null; - if (data.requestId) { - subscription = this.subscriptions.get(data.requestId); - } - switch (data.op) { - case OP_EVENTS.CONNECTED: - if (this.state === CLIENT_STATE.RECONNECTING) { - this.resubscribe(); - } - this.emit(CLIENT_EMMITER_TYPES.OPEN); - this.id = data.clientId; - this.connectPromise.resolve(); - this.state = CLIENT_STATE.CONNECTED; - break; - case OP_EVENTS.SUBSCRIBED: - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); - } - break; - case OP_EVENTS.ERROR: - if (data.requestId) { - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); - } - } else { - this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); - } - break; - case OP_EVENTS.UNSUBSCRIBED: - // We have already deleted subscription in unsubscribe(), do nothing here - break; - default: - // create, update, enter, leave, delete cases - var className = data.object.className; - // Delete the extrea __type and className fields during transfer to full JSON - delete data.object.__type; - delete data.object.className; - var parseObject = new _ParseObject2.default(className); - parseObject._finishFetch(data.object); - if (!subscription) { - break; - } - subscription.emit(data.op, parseObject); - } - } - }, { - key: '_handleWebSocketClose', - value: function () { - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.CLOSED; - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - // Notify each subscription about the close - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = (0, _getIterator3.default)(this.subscriptions.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var subscription = _step2.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - this._handleReconnect(); - } - }, { - key: '_handleWebSocketError', - value: function (error) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, error); - var _iteratorNormalCompletion3 = true; - var _didIteratorError3 = false; - var _iteratorError3 = undefined; - - try { - for (var _iterator3 = (0, _getIterator3.default)(this.subscriptions.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { - var subscription = _step3.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); - } - } catch (err) { - _didIteratorError3 = true; - _iteratorError3 = err; - } finally { - try { - if (!_iteratorNormalCompletion3 && _iterator3.return) { - _iterator3.return(); - } - } finally { - if (_didIteratorError3) { - throw _iteratorError3; - } - } - } - - this._handleReconnect(); - } - }, { - key: '_handleReconnect', - value: function () { - var _this6 = this; - - // if closed or currently reconnecting we stop attempting to reconnect - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - - this.state = CLIENT_STATE.RECONNECTING; - var time = generateInterval(this.attempts); - - // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. - // we're unable to distinguish different between close/error when we're unable to reconnect therefore - // we try to reonnect in both cases - // server side ws and browser WebSocket behave differently in when close/error get triggered - - if (this.reconnectHandle) { - clearTimeout(this.reconnectHandle); - } - - this.reconnectHandle = setTimeout(function () { - _this6.attempts++; - _this6.connectPromise = new _ParsePromise2.default(); - _this6.open(); - }.bind(this), time); - } - }]); - return LiveQueryClient; -}(_EventEmitter3.default); - -exports.default = LiveQueryClient; -},{"./EventEmitter":4,"./LiveQuerySubscription":8,"./ParseObject":18,"./ParsePromise":20,"babel-runtime/core-js/get-iterator":43,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/map":45,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],8:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _EventEmitter2 = _dereq_('./EventEmitter'); - -var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new LiveQuery Subscription. - * Extends events.EventEmitter - * cloud functions. - * - * @constructor - * @param {string} id - subscription id - * @param {string} query - query to subscribe to - * @param {string} sessionToken - optional session token - * - *

                  Open Event - When you call query.subscribe(), we send a subscribe request to - * the LiveQuery server, when we get the confirmation from the LiveQuery server, - * this event will be emitted. When the client loses WebSocket connection to the - * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we - * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, - * you'll also get this event. - * - *

                  - * subscription.on('open', () => {
                  - * 
                  - * });

                  - * - *

                  Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, - * you'll get this event. The object is the ParseObject which is created. - * - *

                  - * subscription.on('create', (object) => {
                  - * 
                  - * });

                  - * - *

                  Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe - * is updated (The ParseObject fulfills the ParseQuery before and after changes), - * you'll get this event. The object is the ParseObject which is updated. - * Its content is the latest value of the ParseObject. - * - *

                  - * subscription.on('update', (object) => {
                  - * 
                  - * });

                  - * - *

                  Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery - * but its new value fulfills the ParseQuery, you'll get this event. The object is the - * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                  - * subscription.on('enter', (object) => {
                  - * 
                  - * });

                  - * - * - *

                  Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value - * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject - * which leaves the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                  - * subscription.on('leave', (object) => {
                  - * 
                  - * });

                  - * - * - *

                  Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll - * get this event. The object is the ParseObject which is deleted. - * - *

                  - * subscription.on('delete', (object) => {
                  - * 
                  - * });

                  - * - * - *

                  Close Event - When the client loses the WebSocket connection to the LiveQuery - * server and we stop receiving events, you'll get this event. - * - *

                  - * subscription.on('close', () => {
                  - * 
                  - * });

                  - * - * - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -var Subscription = function (_EventEmitter) { - (0, _inherits3.default)(Subscription, _EventEmitter); - - function Subscription(id, query, sessionToken) { - (0, _classCallCheck3.default)(this, Subscription); - - var _this2 = (0, _possibleConstructorReturn3.default)(this, (Subscription.__proto__ || (0, _getPrototypeOf2.default)(Subscription)).call(this)); - - _this2.id = id; - _this2.query = query; - _this2.sessionToken = sessionToken; - return _this2; - } - - /** - * @method unsubscribe - */ - - (0, _createClass3.default)(Subscription, [{ - key: 'unsubscribe', - value: function () { - var _this3 = this; - - var _this = this; - _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient().then(function (liveQueryClient) { - liveQueryClient.unsubscribe(_this); - _this.emit('close'); - _this3.resolve(); - }); - } - }]); - return Subscription; -}(_EventEmitter3.default); - -exports.default = Subscription; -},{"./CoreManager":3,"./EventEmitter":4,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],9:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.defaultState = defaultState; -exports.setServerData = setServerData; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _TaskQueue = _dereq_('./TaskQueue'); - -var _TaskQueue2 = _interopRequireDefault(_TaskQueue); - -var _ParseOp = _dereq_('./ParseOp'); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function defaultState() { - return { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new _TaskQueue2.default(), - existed: false - }; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function setServerData(serverData, attributes) { - for (var _attr in attributes) { - if (typeof attributes[_attr] !== 'undefined') { - serverData[_attr] = attributes[_attr]; - } else { - delete serverData[_attr]; - } - } -} - -function setPendingOp(pendingOps, attr, op) { - var last = pendingOps.length - 1; - if (op) { - pendingOps[last][attr] = op; - } else { - delete pendingOps[last][attr]; - } -} - -function pushPendingState(pendingOps) { - pendingOps.push({}); -} - -function popPendingState(pendingOps) { - var first = pendingOps.shift(); - if (!pendingOps.length) { - pendingOps[0] = {}; - } - return first; -} - -function mergeFirstPendingState(pendingOps) { - var first = popPendingState(pendingOps); - var next = pendingOps[0]; - for (var _attr2 in first) { - if (next[_attr2] && first[_attr2]) { - var merged = next[_attr2].mergeWith(first[_attr2]); - if (merged) { - next[_attr2] = merged; - } - } else { - next[_attr2] = first[_attr2]; - } - } -} - -function estimateAttribute(serverData, pendingOps, className, id, attr) { - var value = serverData[attr]; - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i][attr]) { - if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { - if (id) { - value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); - } - } else { - value = pendingOps[i][attr].applyTo(value); - } - } - } - return value; -} - -function estimateAttributes(serverData, pendingOps, className, id) { - var data = {}; - var attr = void 0; - for (attr in serverData) { - data[attr] = serverData[attr]; - } - for (var i = 0; i < pendingOps.length; i++) { - for (attr in pendingOps[i]) { - if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { - if (id) { - data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); - } - } else { - data[attr] = pendingOps[i][attr].applyTo(data[attr]); - } - } - } - return data; -} - -function commitServerChanges(serverData, objectCache, changes) { - for (var _attr3 in changes) { - var val = changes[_attr3]; - serverData[_attr3] = val; - if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof _ParseObject2.default) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { - var json = (0, _encode2.default)(val, false, true); - objectCache[_attr3] = (0, _stringify2.default)(json); - } - } -} -},{"./ParseFile":14,"./ParseObject":18,"./ParseOp":19,"./ParsePromise":20,"./ParseRelation":22,"./TaskQueue":31,"./encode":36,"babel-runtime/core-js/json/stringify":44,"babel-runtime/helpers/typeof":61}],10:[function(_dereq_,module,exports){ -'use strict'; - -var _decode = _dereq_('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _InstallationController = _dereq_('./InstallationController'); - -var _InstallationController2 = _interopRequireDefault(_InstallationController); - -var _ParseOp = _dereq_('./ParseOp'); - -var ParseOp = _interopRequireWildcard(_ParseOp); - -var _RESTController = _dereq_('./RESTController'); - -var _RESTController2 = _interopRequireDefault(_RESTController); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains all Parse API classes and functions. - * @class Parse - * @static - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var Parse = { - /** - * Call this method first to set up your authentication tokens for Parse. - * You can get your keys from the Data Browser on parse.com. - * @method initialize - * @param {String} applicationId Your Parse Application ID. - * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) - * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) - * @static - */ - initialize: function (applicationId, javaScriptKey) { - if ('browser' === 'browser' && _CoreManager2.default.get('IS_NODE')) { - console.log('It looks like you\'re using the browser version of the SDK in a ' + 'node.js environment. You should require(\'parse/node\') instead.'); - } - Parse._initialize(applicationId, javaScriptKey); - }, - _initialize: function (applicationId, javaScriptKey, masterKey) { - _CoreManager2.default.set('APPLICATION_ID', applicationId); - _CoreManager2.default.set('JAVASCRIPT_KEY', javaScriptKey); - _CoreManager2.default.set('MASTER_KEY', masterKey); - _CoreManager2.default.set('USE_MASTER_KEY', false); - } -}; - -/** These legacy setters may eventually be deprecated **/ -Object.defineProperty(Parse, 'applicationId', { - get: function () { - return _CoreManager2.default.get('APPLICATION_ID'); - }, - set: function (value) { - _CoreManager2.default.set('APPLICATION_ID', value); - } -}); -Object.defineProperty(Parse, 'javaScriptKey', { - get: function () { - return _CoreManager2.default.get('JAVASCRIPT_KEY'); - }, - set: function (value) { - _CoreManager2.default.set('JAVASCRIPT_KEY', value); - } -}); -Object.defineProperty(Parse, 'masterKey', { - get: function () { - return _CoreManager2.default.get('MASTER_KEY'); - }, - set: function (value) { - _CoreManager2.default.set('MASTER_KEY', value); - } -}); -Object.defineProperty(Parse, 'serverURL', { - get: function () { - return _CoreManager2.default.get('SERVER_URL'); - }, - set: function (value) { - _CoreManager2.default.set('SERVER_URL', value); - } -}); -Object.defineProperty(Parse, 'liveQueryServerURL', { - get: function () { - return _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); - }, - set: function (value) { - _CoreManager2.default.set('LIVEQUERY_SERVER_URL', value); - } -}); -/** End setters **/ - -Parse.ACL = _dereq_('./ParseACL').default; -Parse.Analytics = _dereq_('./Analytics'); -Parse.Cloud = _dereq_('./Cloud'); -Parse.CoreManager = _dereq_('./CoreManager'); -Parse.Config = _dereq_('./ParseConfig').default; -Parse.Error = _dereq_('./ParseError').default; -Parse.FacebookUtils = _dereq_('./FacebookUtils').default; -Parse.File = _dereq_('./ParseFile').default; -Parse.GeoPoint = _dereq_('./ParseGeoPoint').default; -Parse.Installation = _dereq_('./ParseInstallation').default; -Parse.Object = _dereq_('./ParseObject').default; -Parse.Op = { - Set: ParseOp.SetOp, - Unset: ParseOp.UnsetOp, - Increment: ParseOp.IncrementOp, - Add: ParseOp.AddOp, - Remove: ParseOp.RemoveOp, - AddUnique: ParseOp.AddUniqueOp, - Relation: ParseOp.RelationOp -}; -Parse.Promise = _dereq_('./ParsePromise').default; -Parse.Push = _dereq_('./Push'); -Parse.Query = _dereq_('./ParseQuery').default; -Parse.Relation = _dereq_('./ParseRelation').default; -Parse.Role = _dereq_('./ParseRole').default; -Parse.Session = _dereq_('./ParseSession').default; -Parse.Storage = _dereq_('./Storage'); -Parse.User = _dereq_('./ParseUser').default; -Parse.LiveQuery = _dereq_('./ParseLiveQuery').default; -Parse.LiveQueryClient = _dereq_('./LiveQueryClient').default; - -Parse._request = function () { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _CoreManager2.default.getRESTController().request.apply(null, args); -}; -Parse._ajax = function () { - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return _CoreManager2.default.getRESTController().ajax.apply(null, args); -}; -// We attempt to match the signatures of the legacy versions of these methods -Parse._decode = function (_, value) { - return (0, _decode2.default)(value); -}; -Parse._encode = function (value, _, disallowObjects) { - return (0, _encode2.default)(value, disallowObjects); -}; -Parse._getInstallationId = function () { - return _CoreManager2.default.getInstallationController().currentInstallationId(); -}; - -_CoreManager2.default.setInstallationController(_InstallationController2.default); -_CoreManager2.default.setRESTController(_RESTController2.default); - -// For legacy requires, of the form `var Parse = require('parse').Parse` -Parse.Parse = Parse; - -module.exports = Parse; -},{"./Analytics":1,"./Cloud":2,"./CoreManager":3,"./FacebookUtils":5,"./InstallationController":6,"./LiveQueryClient":7,"./ParseACL":11,"./ParseConfig":12,"./ParseError":13,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseInstallation":16,"./ParseLiveQuery":17,"./ParseObject":18,"./ParseOp":19,"./ParsePromise":20,"./ParseQuery":21,"./ParseRelation":22,"./ParseRole":23,"./ParseSession":24,"./ParseUser":25,"./Push":26,"./RESTController":27,"./Storage":29,"./decode":35,"./encode":36}],11:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _keys = _dereq_('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParseRole = _dereq_('./ParseRole'); - -var _ParseRole2 = _interopRequireDefault(_ParseRole); - -var _ParseUser = _dereq_('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var PUBLIC_KEY = '*'; - -/** - * Creates a new ACL. - * If no argument is given, the ACL has no permissions for anyone. - * If the argument is a Parse.User, the ACL will have read and write - * permission for only that user. - * If the argument is any other JSON object, that object will be interpretted - * as a serialized ACL created with toJSON(). - * @class Parse.ACL - * @constructor - * - *

                  An ACL, or Access Control List can be added to any - * Parse.Object to restrict access to only a subset of users - * of your application.

                  - */ - -var ParseACL = function () { - function ParseACL(arg1) { - (0, _classCallCheck3.default)(this, ParseACL); - - this.permissionsById = {}; - if (arg1 && (typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { - if (arg1 instanceof _ParseUser2.default) { - this.setReadAccess(arg1, true); - this.setWriteAccess(arg1, true); - } else { - for (var userId in arg1) { - var accessList = arg1[userId]; - if (typeof userId !== 'string') { - throw new TypeError('Tried to create an ACL with an invalid user id.'); - } - this.permissionsById[userId] = {}; - for (var permission in accessList) { - var allowed = accessList[permission]; - if (permission !== 'read' && permission !== 'write') { - throw new TypeError('Tried to create an ACL with an invalid permission type.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('Tried to create an ACL with an invalid permission value.'); - } - this.permissionsById[userId][permission] = allowed; - } - } - } - } else if (typeof arg1 === 'function') { - throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); - } - } - - /** - * Returns a JSON-encoded version of the ACL. - * @method toJSON - * @return {Object} - */ - - (0, _createClass3.default)(ParseACL, [{ - key: 'toJSON', - value: function () { - var permissions = {}; - for (var p in this.permissionsById) { - permissions[p] = this.permissionsById[p]; - } - return permissions; - } - - /** - * Returns whether this ACL is equal to another object - * @method equals - * @param other The other object to compare to - * @return {Boolean} - */ - - }, { - key: 'equals', - value: function (other) { - if (!(other instanceof ParseACL)) { - return false; - } - var users = (0, _keys2.default)(this.permissionsById); - var otherUsers = (0, _keys2.default)(other.permissionsById); - if (users.length !== otherUsers.length) { - return false; - } - for (var u in this.permissionsById) { - if (!other.permissionsById[u]) { - return false; - } - if (this.permissionsById[u].read !== other.permissionsById[u].read) { - return false; - } - if (this.permissionsById[u].write !== other.permissionsById[u].write) { - return false; - } - } - return true; - } - }, { - key: '_setAccess', - value: function (accessType, userId, allowed) { - if (userId instanceof _ParseUser2.default) { - userId = userId.id; - } else if (userId instanceof _ParseRole2.default) { - var name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - if (typeof userId !== 'string') { - throw new TypeError('userId must be a string.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('allowed must be either true or false.'); - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - if (!allowed) { - // The user already doesn't have this permission, so no action is needed - return; - } else { - permissions = {}; - this.permissionsById[userId] = permissions; - } - } - - if (allowed) { - this.permissionsById[userId][accessType] = true; - } else { - delete permissions[accessType]; - if ((0, _keys2.default)(permissions).length === 0) { - delete this.permissionsById[userId]; - } - } - } - }, { - key: '_getAccess', - value: function (accessType, userId) { - if (userId instanceof _ParseUser2.default) { - userId = userId.id; - if (!userId) { - throw new Error('Cannot get access for a ParseUser without an ID'); - } - } else if (userId instanceof _ParseRole2.default) { - var name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - return false; - } - return !!permissions[accessType]; - } - - /** - * Sets whether the given user is allowed to read this object. - * @method setReadAccess - * @param userId An instance of Parse.User or its objectId. - * @param {Boolean} allowed Whether that user should have read access. - */ - - }, { - key: 'setReadAccess', - value: function (userId, allowed) { - this._setAccess('read', userId, allowed); - } - - /** - * Get whether the given user id is *explicitly* allowed to read this object. - * Even if this returns false, the user may still be able to access it if - * getPublicReadAccess returns true or a role that the user belongs to has - * write access. - * @method getReadAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - - }, { - key: 'getReadAccess', - value: function (userId) { - return this._getAccess('read', userId); - } - - /** - * Sets whether the given user id is allowed to write this object. - * @method setWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. - * @param {Boolean} allowed Whether that user should have write access. - */ - - }, { - key: 'setWriteAccess', - value: function (userId, allowed) { - this._setAccess('write', userId, allowed); - } - - /** - * Gets whether the given user id is *explicitly* allowed to write this object. - * Even if this returns false, the user may still be able to write it if - * getPublicWriteAccess returns true or a role that the user belongs to has - * write access. - * @method getWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - - }, { - key: 'getWriteAccess', - value: function (userId) { - return this._getAccess('write', userId); - } - - /** - * Sets whether the public is allowed to read this object. - * @method setPublicReadAccess - * @param {Boolean} allowed - */ - - }, { - key: 'setPublicReadAccess', - value: function (allowed) { - this.setReadAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to read this object. - * @method getPublicReadAccess - * @return {Boolean} - */ - - }, { - key: 'getPublicReadAccess', - value: function () { - return this.getReadAccess(PUBLIC_KEY); - } - - /** - * Sets whether the public is allowed to write this object. - * @method setPublicWriteAccess - * @param {Boolean} allowed - */ - - }, { - key: 'setPublicWriteAccess', - value: function (allowed) { - this.setWriteAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to write this object. - * @method getPublicWriteAccess - * @return {Boolean} - */ - - }, { - key: 'getPublicWriteAccess', - value: function () { - return this.getWriteAccess(PUBLIC_KEY); - } - - /** - * Gets whether users belonging to the given role are allowed - * to read this object. Even if this returns false, the role may - * still be able to write it if a parent role has read access. - * - * @method getRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has read access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'getRoleReadAccess', - value: function (role) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getReadAccess('role:' + role); - } - - /** - * Gets whether users belonging to the given role are allowed - * to write this object. Even if this returns false, the role may - * still be able to write it if a parent role has write access. - * - * @method getRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has write access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'getRoleWriteAccess', - value: function (role) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getWriteAccess('role:' + role); - } - - /** - * Sets whether users belonging to the given role are allowed - * to read this object. - * - * @method setRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can read this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'setRoleReadAccess', - value: function (role, allowed) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setReadAccess('role:' + role, allowed); - } - - /** - * Sets whether users belonging to the given role are allowed - * to write this object. - * - * @method setRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can write this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'setRoleWriteAccess', - value: function (role, allowed) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setWriteAccess('role:' + role, allowed); - } - }]); - return ParseACL; -}(); - -exports.default = ParseACL; -},{"./ParseRole":23,"./ParseUser":25,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],12:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = _dereq_('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _escape2 = _dereq_('./escape'); - -var _escape3 = _interopRequireDefault(_escape2); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = _dereq_('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Parse.Config is a local representation of configuration data that - * can be set from the Parse dashboard. - * - * @class Parse.Config - * @constructor - */ - -var ParseConfig = function () { - function ParseConfig() { - (0, _classCallCheck3.default)(this, ParseConfig); - - this.attributes = {}; - this._escapedAttributes = {}; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The name of an attribute. - */ - - (0, _createClass3.default)(ParseConfig, [{ - key: 'get', - value: function (attr) { - return this.attributes[attr]; - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The name of an attribute. - */ - - }, { - key: 'escape', - value: function (attr) { - var html = this._escapedAttributes[attr]; - if (html) { - return html; - } - var val = this.attributes[attr]; - var escaped = ''; - if (val != null) { - escaped = (0, _escape3.default)(val.toString()); - } - this._escapedAttributes[attr] = escaped; - return escaped; - } - - /** - * Retrieves the most recently-fetched configuration object, either from - * memory or from local storage if necessary. - * - * @method current - * @static - * @return {Config} The most recently-fetched Parse.Config if it - * exists, else an empty Parse.Config. - */ - - }], [{ - key: 'current', - value: function () { - var controller = _CoreManager2.default.getConfigController(); - return controller.current(); - } - - /** - * Gets a new configuration object from the server. - * @method get - * @static - * @param {Object} options A Backbone-style options object. - * Valid options are:
                    - *
                  • success: Function to call when the get completes successfully. - *
                  • error: Function to call when the get fails. - *
                  - * @return {Parse.Promise} A promise that is resolved with a newly-created - * configuration object when the get completes. - */ - - }, { - key: 'get', - value: function (options) { - options = options || {}; - - var controller = _CoreManager2.default.getConfigController(); - return controller.get()._thenRunCallbacks(options); - } - }]); - return ParseConfig; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseConfig; - -var currentConfig = null; - -var CURRENT_CONFIG_KEY = 'currentConfig'; - -function decodePayload(data) { - try { - var json = JSON.parse(data); - if (json && (typeof json === 'undefined' ? 'undefined' : (0, _typeof3.default)(json)) === 'object') { - return (0, _decode2.default)(json); - } - } catch (e) { - return null; - } -} - -var DefaultController = { - current: function () { - if (currentConfig) { - return currentConfig; - } - - var config = new ParseConfig(); - var storagePath = _Storage2.default.generatePath(CURRENT_CONFIG_KEY); - var configData; - if (!_Storage2.default.async()) { - configData = _Storage2.default.getItem(storagePath); - - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - } - // Return a promise for async storage controllers - return _Storage2.default.getItemAsync(storagePath).then(function (configData) { - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - }); - }, - get: function () { - var RESTController = _CoreManager2.default.getRESTController(); - - return RESTController.request('GET', 'config', {}, {}).then(function (response) { - if (!response || !response.params) { - var error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Config JSON response invalid.'); - return _ParsePromise2.default.error(error); - } - - var config = new ParseConfig(); - config.attributes = {}; - for (var attr in response.params) { - config.attributes[attr] = (0, _decode2.default)(response.params[attr]); - } - currentConfig = config; - return _Storage2.default.setItemAsync(_Storage2.default.generatePath(CURRENT_CONFIG_KEY), (0, _stringify2.default)(response.params)).then(function () { - return config; - }); - }); - } -}; - -_CoreManager2.default.setConfigController(DefaultController); -},{"./CoreManager":3,"./ParseError":13,"./ParsePromise":20,"./Storage":29,"./decode":35,"./encode":36,"./escape":38,"babel-runtime/core-js/json/stringify":44,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],13:[function(_dereq_,module,exports){ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = _dereq_("babel-runtime/helpers/classCallCheck"); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/** - * Constructs a new Parse.Error object with the given code and message. - * @class Parse.Error - * @constructor - * @param {Number} code An error code constant from Parse.Error. - * @param {String} message A detailed description of the error. - */ -var ParseError = function ParseError(code, message) { - (0, _classCallCheck3.default)(this, ParseError); - - this.code = code; - this.message = message; -}; - -/** - * Error code indicating some error other than those enumerated here. - * @property OTHER_CAUSE - * @static - * @final - */ - -exports.default = ParseError; -ParseError.OTHER_CAUSE = -1; - -/** - * Error code indicating that something has gone wrong with the server. - * If you get this error code, it is Parse's fault. Contact us at - * https://parse.com/help - * @property INTERNAL_SERVER_ERROR - * @static - * @final - */ -ParseError.INTERNAL_SERVER_ERROR = 1; - -/** - * Error code indicating the connection to the Parse servers failed. - * @property CONNECTION_FAILED - * @static - * @final - */ -ParseError.CONNECTION_FAILED = 100; - -/** - * Error code indicating the specified object doesn't exist. - * @property OBJECT_NOT_FOUND - * @static - * @final - */ -ParseError.OBJECT_NOT_FOUND = 101; - -/** - * Error code indicating you tried to query with a datatype that doesn't - * support it, like exact matching an array or object. - * @property INVALID_QUERY - * @static - * @final - */ -ParseError.INVALID_QUERY = 102; - -/** - * Error code indicating a missing or invalid classname. Classnames are - * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the - * only valid characters. - * @property INVALID_CLASS_NAME - * @static - * @final - */ -ParseError.INVALID_CLASS_NAME = 103; - -/** - * Error code indicating an unspecified object id. - * @property MISSING_OBJECT_ID - * @static - * @final - */ -ParseError.MISSING_OBJECT_ID = 104; - -/** - * Error code indicating an invalid key name. Keys are case-sensitive. They - * must start with a letter, and a-zA-Z0-9_ are the only valid characters. - * @property INVALID_KEY_NAME - * @static - * @final - */ -ParseError.INVALID_KEY_NAME = 105; - -/** - * Error code indicating a malformed pointer. You should not see this unless - * you have been mucking about changing internal Parse code. - * @property INVALID_POINTER - * @static - * @final - */ -ParseError.INVALID_POINTER = 106; - -/** - * Error code indicating that badly formed JSON was received upstream. This - * either indicates you have done something unusual with modifying how - * things encode to JSON, or the network is failing badly. - * @property INVALID_JSON - * @static - * @final - */ -ParseError.INVALID_JSON = 107; - -/** - * Error code indicating that the feature you tried to access is only - * available internally for testing purposes. - * @property COMMAND_UNAVAILABLE - * @static - * @final - */ -ParseError.COMMAND_UNAVAILABLE = 108; - -/** - * You must call Parse.initialize before using the Parse library. - * @property NOT_INITIALIZED - * @static - * @final - */ -ParseError.NOT_INITIALIZED = 109; - -/** - * Error code indicating that a field was set to an inconsistent type. - * @property INCORRECT_TYPE - * @static - * @final - */ -ParseError.INCORRECT_TYPE = 111; - -/** - * Error code indicating an invalid channel name. A channel name is either - * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ - * characters and starts with a letter. - * @property INVALID_CHANNEL_NAME - * @static - * @final - */ -ParseError.INVALID_CHANNEL_NAME = 112; - -/** - * Error code indicating that push is misconfigured. - * @property PUSH_MISCONFIGURED - * @static - * @final - */ -ParseError.PUSH_MISCONFIGURED = 115; - -/** - * Error code indicating that the object is too large. - * @property OBJECT_TOO_LARGE - * @static - * @final - */ -ParseError.OBJECT_TOO_LARGE = 116; - -/** - * Error code indicating that the operation isn't allowed for clients. - * @property OPERATION_FORBIDDEN - * @static - * @final - */ -ParseError.OPERATION_FORBIDDEN = 119; - -/** - * Error code indicating the result was not found in the cache. - * @property CACHE_MISS - * @static - * @final - */ -ParseError.CACHE_MISS = 120; - -/** - * Error code indicating that an invalid key was used in a nested - * JSONObject. - * @property INVALID_NESTED_KEY - * @static - * @final - */ -ParseError.INVALID_NESTED_KEY = 121; - -/** - * Error code indicating that an invalid filename was used for ParseFile. - * A valid file name contains only a-zA-Z0-9_. characters and is between 1 - * and 128 characters. - * @property INVALID_FILE_NAME - * @static - * @final - */ -ParseError.INVALID_FILE_NAME = 122; - -/** - * Error code indicating an invalid ACL was provided. - * @property INVALID_ACL - * @static - * @final - */ -ParseError.INVALID_ACL = 123; - -/** - * Error code indicating that the request timed out on the server. Typically - * this indicates that the request is too expensive to run. - * @property TIMEOUT - * @static - * @final - */ -ParseError.TIMEOUT = 124; - -/** - * Error code indicating that the email address was invalid. - * @property INVALID_EMAIL_ADDRESS - * @static - * @final - */ -ParseError.INVALID_EMAIL_ADDRESS = 125; - -/** - * Error code indicating a missing content type. - * @property MISSING_CONTENT_TYPE - * @static - * @final - */ -ParseError.MISSING_CONTENT_TYPE = 126; - -/** - * Error code indicating a missing content length. - * @property MISSING_CONTENT_LENGTH - * @static - * @final - */ -ParseError.MISSING_CONTENT_LENGTH = 127; - -/** - * Error code indicating an invalid content length. - * @property INVALID_CONTENT_LENGTH - * @static - * @final - */ -ParseError.INVALID_CONTENT_LENGTH = 128; - -/** - * Error code indicating a file that was too large. - * @property FILE_TOO_LARGE - * @static - * @final - */ -ParseError.FILE_TOO_LARGE = 129; - -/** - * Error code indicating an error saving a file. - * @property FILE_SAVE_ERROR - * @static - * @final - */ -ParseError.FILE_SAVE_ERROR = 130; - -/** - * Error code indicating that a unique field was given a value that is - * already taken. - * @property DUPLICATE_VALUE - * @static - * @final - */ -ParseError.DUPLICATE_VALUE = 137; - -/** - * Error code indicating that a role's name is invalid. - * @property INVALID_ROLE_NAME - * @static - * @final - */ -ParseError.INVALID_ROLE_NAME = 139; - -/** - * Error code indicating that an application quota was exceeded. Upgrade to - * resolve. - * @property EXCEEDED_QUOTA - * @static - * @final - */ -ParseError.EXCEEDED_QUOTA = 140; - -/** - * Error code indicating that a Cloud Code script failed. - * @property SCRIPT_FAILED - * @static - * @final - */ -ParseError.SCRIPT_FAILED = 141; - -/** - * Error code indicating that a Cloud Code validation failed. - * @property VALIDATION_ERROR - * @static - * @final - */ -ParseError.VALIDATION_ERROR = 142; - -/** - * Error code indicating that invalid image data was provided. - * @property INVALID_IMAGE_DATA - * @static - * @final - */ -ParseError.INVALID_IMAGE_DATA = 143; - -/** - * Error code indicating an unsaved file. - * @property UNSAVED_FILE_ERROR - * @static - * @final - */ -ParseError.UNSAVED_FILE_ERROR = 151; - -/** - * Error code indicating an invalid push time. - * @property INVALID_PUSH_TIME_ERROR - * @static - * @final - */ -ParseError.INVALID_PUSH_TIME_ERROR = 152; - -/** - * Error code indicating an error deleting a file. - * @property FILE_DELETE_ERROR - * @static - * @final - */ -ParseError.FILE_DELETE_ERROR = 153; - -/** - * Error code indicating that the application has exceeded its request - * limit. - * @property REQUEST_LIMIT_EXCEEDED - * @static - * @final - */ -ParseError.REQUEST_LIMIT_EXCEEDED = 155; - -/** - * Error code indicating an invalid event name. - * @property INVALID_EVENT_NAME - * @static - * @final - */ -ParseError.INVALID_EVENT_NAME = 160; - -/** - * Error code indicating that the username is missing or empty. - * @property USERNAME_MISSING - * @static - * @final - */ -ParseError.USERNAME_MISSING = 200; - -/** - * Error code indicating that the password is missing or empty. - * @property PASSWORD_MISSING - * @static - * @final - */ -ParseError.PASSWORD_MISSING = 201; - -/** - * Error code indicating that the username has already been taken. - * @property USERNAME_TAKEN - * @static - * @final - */ -ParseError.USERNAME_TAKEN = 202; - -/** - * Error code indicating that the email has already been taken. - * @property EMAIL_TAKEN - * @static - * @final - */ -ParseError.EMAIL_TAKEN = 203; - -/** - * Error code indicating that the email is missing, but must be specified. - * @property EMAIL_MISSING - * @static - * @final - */ -ParseError.EMAIL_MISSING = 204; - -/** - * Error code indicating that a user with the specified email was not found. - * @property EMAIL_NOT_FOUND - * @static - * @final - */ -ParseError.EMAIL_NOT_FOUND = 205; - -/** - * Error code indicating that a user object without a valid session could - * not be altered. - * @property SESSION_MISSING - * @static - * @final - */ -ParseError.SESSION_MISSING = 206; - -/** - * Error code indicating that a user can only be created through signup. - * @property MUST_CREATE_USER_THROUGH_SIGNUP - * @static - * @final - */ -ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; - -/** - * Error code indicating that an an account being linked is already linked - * to another user. - * @property ACCOUNT_ALREADY_LINKED - * @static - * @final - */ -ParseError.ACCOUNT_ALREADY_LINKED = 208; - -/** - * Error code indicating that the current session token is invalid. - * @property INVALID_SESSION_TOKEN - * @static - * @final - */ -ParseError.INVALID_SESSION_TOKEN = 209; - -/** - * Error code indicating that a user cannot be linked to an account because - * that account's id could not be found. - * @property LINKED_ID_MISSING - * @static - * @final - */ -ParseError.LINKED_ID_MISSING = 250; - -/** - * Error code indicating that a user with a linked (e.g. Facebook) account - * has an invalid session. - * @property INVALID_LINKED_SESSION - * @static - * @final - */ -ParseError.INVALID_LINKED_SESSION = 251; - -/** - * Error code indicating that a service being linked (e.g. Facebook or - * Twitter) is unsupported. - * @property UNSUPPORTED_SERVICE - * @static - * @final - */ -ParseError.UNSUPPORTED_SERVICE = 252; - -/** - * Error code indicating that there were multiple errors. Aggregate errors - * have an "errors" property, which is an array of error objects with more - * detail about each error that occurred. - * @property AGGREGATE_ERROR - * @static - * @final - */ -ParseError.AGGREGATE_ERROR = 600; - -/** - * Error code indicating the client was unable to read an input file. - * @property FILE_READ_ERROR - * @static - * @final - */ -ParseError.FILE_READ_ERROR = 601; - -/** - * Error code indicating a real error code is unavailable because - * we had to use an XDomainRequest object to allow CORS requests in - * Internet Explorer, which strips the body from HTTP responses that have - * a non-2XX status code. - * @property X_DOMAIN_REQUEST - * @static - * @final - */ -ParseError.X_DOMAIN_REQUEST = 602; -},{"babel-runtime/helpers/classCallCheck":56}],14:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; - -function b64Digit(number) { - if (number < 26) { - return String.fromCharCode(65 + number); - } - if (number < 52) { - return String.fromCharCode(97 + (number - 26)); - } - if (number < 62) { - return String.fromCharCode(48 + (number - 52)); - } - if (number === 62) { - return '+'; - } - if (number === 63) { - return '/'; - } - throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); -} - -/** - * A Parse.File is a local representation of a file that is saved to the Parse - * cloud. - * @class Parse.File - * @constructor - * @param name {String} The file's name. This will be prefixed by a unique - * value once the file has finished saving. The file name must begin with - * an alphanumeric character, and consist of alphanumeric characters, - * periods, spaces, underscores, or dashes. - * @param data {Array} The data for the file, as either: - * 1. an Array of byte value Numbers, or - * 2. an Object like { base64: "..." } with a base64-encoded String. - * 3. a File object selected with a file upload control. (3) only works - * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. - * For example:
                  - * var fileUploadControl = $("#profilePhotoFileUpload")[0];
                  - * if (fileUploadControl.files.length > 0) {
                  - *   var file = fileUploadControl.files[0];
                  - *   var name = "photo.jpg";
                  - *   var parseFile = new Parse.File(name, file);
                  - *   parseFile.save().then(function() {
                  - *     // The file has been saved to Parse.
                  - *   }, function(error) {
                  - *     // The file either could not be read, or could not be saved to Parse.
                  - *   });
                  - * }
                  - * @param type {String} Optional Content-Type header to use for the file. If - * this is omitted, the content type will be inferred from the name's - * extension. - */ - -var ParseFile = function () { - function ParseFile(name, data, type) { - (0, _classCallCheck3.default)(this, ParseFile); - - var specifiedType = type || ''; - - this._name = name; - - if (data !== undefined) { - if (Array.isArray(data)) { - this._source = { - format: 'base64', - base64: ParseFile.encodeBase64(data), - type: specifiedType - }; - } else if (typeof File !== 'undefined' && data instanceof File) { - this._source = { - format: 'file', - file: data, - type: specifiedType - }; - } else if (data && typeof data.base64 === 'string') { - var _base = data.base64; - var commaIndex = _base.indexOf(','); - - if (commaIndex !== -1) { - var matches = dataUriRegexp.exec(_base.slice(0, commaIndex + 1)); - // if data URI with type and charset, there will be 4 matches. - this._source = { - format: 'base64', - base64: _base.slice(commaIndex + 1), - type: matches[1] - }; - } else { - this._source = { - format: 'base64', - base64: _base, - type: specifiedType - }; - } - } else { - throw new TypeError('Cannot create a Parse.File with that data.'); - } - } - } - - /** - * Gets the name of the file. Before save is called, this is the filename - * given by the user. After save is called, that name gets prefixed with a - * unique identifier. - * @method name - * @return {String} - */ - - (0, _createClass3.default)(ParseFile, [{ - key: 'name', - value: function () { - return this._name; - } - - /** - * Gets the url of the file. It is only available after you save the file or - * after you get the file from a Parse.Object. - * @method url - * @param {Object} options An object to specify url options - * @return {String} - */ - - }, { - key: 'url', - value: function (options) { - options = options || {}; - if (!this._url) { - return; - } - if (options.forceSecure) { - return this._url.replace(/^http:\/\//i, 'https://'); - } else { - return this._url; - } - } - - /** - * Saves the file to the Parse cloud. - * @method save - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} Promise that is resolved when the save finishes. - */ - - }, { - key: 'save', - value: function (options) { - var _this = this; - - options = options || {}; - var controller = _CoreManager2.default.getFileController(); - if (!this._previousSave) { - if (this._source.format === 'file') { - this._previousSave = controller.saveFile(this._name, this._source).then(function (res) { - _this._name = res.name; - _this._url = res.url; - return _this; - }); - } else { - this._previousSave = controller.saveBase64(this._name, this._source).then(function (res) { - _this._name = res.name; - _this._url = res.url; - return _this; - }); - } - } - if (this._previousSave) { - return this._previousSave._thenRunCallbacks(options); - } - } - }, { - key: 'toJSON', - value: function () { - return { - __type: 'File', - name: this._name, - url: this._url - }; - } - }, { - key: 'equals', - value: function (other) { - if (this === other) { - return true; - } - // Unsaved Files are never equal, since they will be saved to different URLs - return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; - } - }], [{ - key: 'fromJSON', - value: function (obj) { - if (obj.__type !== 'File') { - throw new TypeError('JSON object does not represent a ParseFile'); - } - var file = new ParseFile(obj.name); - file._url = obj.url; - return file; - } - }, { - key: 'encodeBase64', - value: function (bytes) { - var chunks = []; - chunks.length = Math.ceil(bytes.length / 3); - for (var i = 0; i < chunks.length; i++) { - var b1 = bytes[i * 3]; - var b2 = bytes[i * 3 + 1] || 0; - var b3 = bytes[i * 3 + 2] || 0; - - var has2 = i * 3 + 1 < bytes.length; - var has3 = i * 3 + 2 < bytes.length; - - chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); - } - - return chunks.join(''); - } - }]); - return ParseFile; -}(); - -exports.default = ParseFile; - -var DefaultController = { - saveFile: function (name, source) { - if (source.format !== 'file') { - throw new Error('saveFile can only be used with File-type sources.'); - } - // To directly upload a File, we use a REST-style AJAX request - var headers = { - 'X-Parse-Application-ID': _CoreManager2.default.get('APPLICATION_ID'), - 'X-Parse-JavaScript-Key': _CoreManager2.default.get('JAVASCRIPT_KEY'), - 'Content-Type': source.type || (source.file ? source.file.type : null) - }; - var url = _CoreManager2.default.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += 'files/' + name; - return _CoreManager2.default.getRESTController().ajax('POST', url, source.file, headers); - }, - - saveBase64: function (name, source) { - if (source.format !== 'base64') { - throw new Error('saveBase64 can only be used with Base64-type sources.'); - } - var data = { - base64: source.base64 - }; - if (source.type) { - data._ContentType = source.type; - } - - return _CoreManager2.default.getRESTController().request('POST', 'files/' + name, data); - } -}; - -_CoreManager2.default.setFileController(DefaultController); -},{"./CoreManager":3,"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],15:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new GeoPoint with any of the following forms:
                  - *
                  - *   new GeoPoint(otherGeoPoint)
                  - *   new GeoPoint(30, 30)
                  - *   new GeoPoint([30, 30])
                  - *   new GeoPoint({latitude: 30, longitude: 30})
                  - *   new GeoPoint()  // defaults to (0, 0)
                  - *   
                  - * @class Parse.GeoPoint - * @constructor - * - *

                  Represents a latitude / longitude point that may be associated - * with a key in a ParseObject or used as a reference point for geo queries. - * This allows proximity-based queries on the key.

                  - * - *

                  Only one key in a class may contain a GeoPoint.

                  - * - *

                  Example:

                  - *   var point = new Parse.GeoPoint(30.0, -20.0);
                  - *   var object = new Parse.Object("PlaceObject");
                  - *   object.set("location", point);
                  - *   object.save();

                  - */ -var ParseGeoPoint = function () { - function ParseGeoPoint(arg1, arg2) { - (0, _classCallCheck3.default)(this, ParseGeoPoint); - - if (Array.isArray(arg1)) { - ParseGeoPoint._validate(arg1[0], arg1[1]); - this._latitude = arg1[0]; - this._longitude = arg1[1]; - } else if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { - ParseGeoPoint._validate(arg1.latitude, arg1.longitude); - this._latitude = arg1.latitude; - this._longitude = arg1.longitude; - } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { - ParseGeoPoint._validate(arg1, arg2); - this._latitude = arg1; - this._longitude = arg2; - } else { - this._latitude = 0; - this._longitude = 0; - } - } - - /** - * North-south portion of the coordinate, in range [-90, 90]. - * Throws an exception if set out of range in a modern browser. - * @property latitude - * @type Number - */ - - (0, _createClass3.default)(ParseGeoPoint, [{ - key: 'toJSON', - - /** - * Returns a JSON representation of the GeoPoint, suitable for Parse. - * @method toJSON - * @return {Object} - */ - value: function () { - ParseGeoPoint._validate(this._latitude, this._longitude); - return { - __type: 'GeoPoint', - latitude: this._latitude, - longitude: this._longitude - }; - } - }, { - key: 'equals', - value: function (other) { - return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; - } - - /** - * Returns the distance from this GeoPoint to another in radians. - * @method radiansTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'radiansTo', - value: function (point) { - var d2r = Math.PI / 180.0; - var lat1rad = this.latitude * d2r; - var long1rad = this.longitude * d2r; - var lat2rad = point.latitude * d2r; - var long2rad = point.longitude * d2r; - - var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); - var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); - // Square of half the straight line chord distance between both points. - var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; - a = Math.min(1.0, a); - return 2 * Math.asin(Math.sqrt(a)); - } - - /** - * Returns the distance from this GeoPoint to another in kilometers. - * @method kilometersTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'kilometersTo', - value: function (point) { - return this.radiansTo(point) * 6371.0; - } - - /** - * Returns the distance from this GeoPoint to another in miles. - * @method milesTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'milesTo', - value: function (point) { - return this.radiansTo(point) * 3958.8; - } - - /** - * Throws an exception if the given lat-long is out of bounds. - */ - - }, { - key: 'latitude', - get: function () { - return this._latitude; - }, - set: function (val) { - ParseGeoPoint._validate(val, this.longitude); - this._latitude = val; - } - - /** - * East-west portion of the coordinate, in range [-180, 180]. - * Throws if set out of range in a modern browser. - * @property longitude - * @type Number - */ - - }, { - key: 'longitude', - get: function () { - return this._longitude; - }, - set: function (val) { - ParseGeoPoint._validate(this.latitude, val); - this._longitude = val; - } - }], [{ - key: '_validate', - value: function (latitude, longitude) { - if (latitude !== latitude || longitude !== longitude) { - throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); - } - if (latitude < -90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); - } - if (latitude > 90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); - } - if (longitude < -180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); - } - if (longitude > 180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); - } - } - - /** - * Creates a GeoPoint with the user's current location, if available. - * Calls options.success with a new GeoPoint instance or calls options.error. - * @method current - * @param {Object} options An object with success and error callbacks. - * @static - */ - - }, { - key: 'current', - value: function (options) { - var promise = new _ParsePromise2.default(); - navigator.geolocation.getCurrentPosition(function (location) { - promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); - }, function (error) { - promise.reject(error); - }); - - return promise._thenRunCallbacks(options); - } - }]); - return ParseGeoPoint; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseGeoPoint; -},{"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],16:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _ParseObject2 = _dereq_('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var Installation = function (_ParseObject) { - (0, _inherits3.default)(Installation, _ParseObject); - - function Installation(attributes) { - (0, _classCallCheck3.default)(this, Installation); - - var _this = (0, _possibleConstructorReturn3.default)(this, (Installation.__proto__ || (0, _getPrototypeOf2.default)(Installation)).call(this, '_Installation')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - return _this; - } - - return Installation; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = Installation; - -_ParseObject3.default.registerSubclass('_Installation', Installation); -},{"./ParseObject":18,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],17:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _EventEmitter = _dereq_('./EventEmitter'); - -var _EventEmitter2 = _interopRequireDefault(_EventEmitter); - -var _LiveQueryClient = _dereq_('./LiveQueryClient'); - -var _LiveQueryClient2 = _interopRequireDefault(_LiveQueryClient); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function open() { - var LiveQueryController = _CoreManager2.default.getLiveQueryController(); - LiveQueryController.open(); -} - -function close() { - var LiveQueryController = _CoreManager2.default.getLiveQueryController(); - LiveQueryController.close(); -} - -/** - * - * We expose three events to help you monitor the status of the WebSocket connection: - * - *

                  Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                  - * Parse.LiveQuery.on('open', () => {
                  - * 
                  - * });

                  - * - *

                  Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                  - * Parse.LiveQuery.on('close', () => {
                  - * 
                  - * });

                  - * - *

                  Error - When some network error or LiveQuery server error happens, you'll get this event. - * - *

                  - * Parse.LiveQuery.on('error', (error) => {
                  - * 
                  - * });

                  - * - * @class Parse.LiveQuery - * @static - * - */ -var LiveQuery = new _EventEmitter2.default(); - -/** - * After open is called, the LiveQuery will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ -LiveQuery.open = open; - -/** - * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). - * This function will close the WebSocket connection to the LiveQuery server, - * cancel the auto reconnect, and unsubscribe all subscriptions based on it. - * If you call query.subscribe() after this, we'll create a new WebSocket - * connection to the LiveQuery server. - * - * @method close - */ - -LiveQuery.close = close; -// Register a default onError callback to make sure we do not crash on error -LiveQuery.on('error', function () {}); - -exports.default = LiveQuery; - -function getSessionToken() { - var controller = _CoreManager2.default.getUserController(); - return controller.currentUserAsync().then(function (currentUser) { - return currentUser ? currentUser.getSessionToken() : undefined; - }); -} - -function getLiveQueryClient() { - return _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient(); -} - -var defaultLiveQueryClient = void 0; -var DefaultLiveQueryController = { - setDefaultLiveQueryClient: function (liveQueryClient) { - defaultLiveQueryClient = liveQueryClient; - }, - getDefaultLiveQueryClient: function () { - if (defaultLiveQueryClient) { - return _ParsePromise2.default.as(defaultLiveQueryClient); - } - - return getSessionToken().then(function (sessionToken) { - var liveQueryServerURL = _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); - - if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL - if (!liveQueryServerURL) { - var tempServerURL = _CoreManager2.default.get('SERVER_URL'); - var protocol = 'ws://'; - // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix - if (tempServerURL.indexOf('https') === 0) { - protocol = 'wss://'; - } - var host = tempServerURL.replace(/^https?:\/\//, ''); - liveQueryServerURL = protocol + host; - _CoreManager2.default.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); - } - - var applicationId = _CoreManager2.default.get('APPLICATION_ID'); - var javascriptKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); - var masterKey = _CoreManager2.default.get('MASTER_KEY'); - // Get currentUser sessionToken if possible - defaultLiveQueryClient = new _LiveQueryClient2.default({ - applicationId: applicationId, - serverURL: liveQueryServerURL, - javascriptKey: javascriptKey, - masterKey: masterKey, - sessionToken: sessionToken - }); - // Register a default onError callback to make sure we do not crash on error - // Cannot create these events on a nested way because of EventEmiiter from React Native - defaultLiveQueryClient.on('error', function (error) { - LiveQuery.emit('error', error); - }); - defaultLiveQueryClient.on('open', function () { - LiveQuery.emit('open'); - }); - defaultLiveQueryClient.on('close', function () { - LiveQuery.emit('close'); - }); - - return defaultLiveQueryClient; - }); - }, - open: function () { - var _this = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this.resolve(liveQueryClient.open()); - }); - }, - close: function () { - var _this2 = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this2.resolve(liveQueryClient.close()); - }); - }, - subscribe: function (query) { - var _this3 = this; - - var subscriptionWrap = new _EventEmitter2.default(); - - getLiveQueryClient().then(function (liveQueryClient) { - if (liveQueryClient.shouldOpen()) { - liveQueryClient.open(); - } - var promiseSessionToken = getSessionToken(); - // new event emitter - return promiseSessionToken.then(function (sessionToken) { - - var subscription = liveQueryClient.subscribe(query, sessionToken); - // enter, leave create, etc - - subscriptionWrap.id = subscription.id; - subscriptionWrap.query = subscription.query; - subscriptionWrap.sessionToken = subscription.sessionToken; - subscriptionWrap.unsubscribe = subscription.unsubscribe; - // Cannot create these events on a nested way because of EventEmiiter from React Native - subscription.on('open', function () { - subscriptionWrap.emit('open'); - }); - subscription.on('create', function (object) { - subscriptionWrap.emit('create', object); - }); - subscription.on('update', function (object) { - subscriptionWrap.emit('update', object); - }); - subscription.on('enter', function (object) { - subscriptionWrap.emit('enter', object); - }); - subscription.on('leave', function (object) { - subscriptionWrap.emit('leave', object); - }); - subscription.on('delete', function (object) { - subscriptionWrap.emit('delete', object); - }); - - _this3.resolve(); - }); - }); - return subscriptionWrap; - }, - unsubscribe: function (subscription) { - var _this4 = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this4.resolve(liveQueryClient.unsubscribe(subscription)); - }); - }, - _clearCachedDefaultClient: function () { - defaultLiveQueryClient = null; - } -}; - -_CoreManager2.default.setLiveQueryController(DefaultLiveQueryController); -},{"./CoreManager":3,"./EventEmitter":4,"./LiveQueryClient":7,"./ParsePromise":20}],18:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _defineProperty = _dereq_('babel-runtime/core-js/object/define-property'); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -var _create = _dereq_('babel-runtime/core-js/object/create'); - -var _create2 = _interopRequireDefault(_create); - -var _freeze = _dereq_('babel-runtime/core-js/object/freeze'); - -var _freeze2 = _interopRequireDefault(_freeze); - -var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _keys = _dereq_('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _canBeSerialized = _dereq_('./canBeSerialized'); - -var _canBeSerialized2 = _interopRequireDefault(_canBeSerialized); - -var _decode = _dereq_('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _equals = _dereq_('./equals'); - -var _equals2 = _interopRequireDefault(_equals); - -var _escape2 = _dereq_('./escape'); - -var _escape3 = _interopRequireDefault(_escape2); - -var _ParseACL = _dereq_('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _parseDate = _dereq_('./parseDate'); - -var _parseDate2 = _interopRequireDefault(_parseDate); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseOp = _dereq_('./ParseOp'); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseQuery = _dereq_('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _SingleInstanceStateController = _dereq_('./SingleInstanceStateController'); - -var SingleInstanceStateController = _interopRequireWildcard(_SingleInstanceStateController); - -var _unique = _dereq_('./unique'); - -var _unique2 = _interopRequireDefault(_unique); - -var _UniqueInstanceStateController = _dereq_('./UniqueInstanceStateController'); - -var UniqueInstanceStateController = _interopRequireWildcard(_UniqueInstanceStateController); - -var _unsavedChildren = _dereq_('./unsavedChildren'); - -var _unsavedChildren2 = _interopRequireDefault(_unsavedChildren); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -// Mapping of class names to constructors, so we can populate objects from the -// server with appropriate subclasses of ParseObject -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var classMap = {}; - -// Global counter for generating unique local Ids -var localCount = 0; -// Global counter for generating unique Ids for non-single-instance objects -var objectCount = 0; -// On web clients, objects are single-instance: any two objects with the same Id -// will have the same attributes. However, this may be dangerous default -// behavior in a server scenario -var singleInstance = !_CoreManager2.default.get('IS_NODE'); -if (singleInstance) { - _CoreManager2.default.setObjectStateController(SingleInstanceStateController); -} else { - _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); -} - -function getServerUrlPath() { - var serverUrl = _CoreManager2.default.get('SERVER_URL'); - if (serverUrl[serverUrl.length - 1] !== '/') { - serverUrl += '/'; - } - var url = serverUrl.replace(/https?:\/\//, ''); - return url.substr(url.indexOf('/')); -} - -/** - * Creates a new model with defined attributes. - * - *

                  You won't normally call this method directly. It is recommended that - * you use a subclass of Parse.Object instead, created by calling - * extend.

                  - * - *

                  However, if you don't want to use a subclass, or aren't sure which - * subclass is appropriate, you can use this form:

                  - *     var object = new Parse.Object("ClassName");
                  - * 
                  - * That is basically equivalent to:
                  - *     var MyClass = Parse.Object.extend("ClassName");
                  - *     var object = new MyClass();
                  - * 

                  - * - * @class Parse.Object - * @constructor - * @param {String} className The class name for the object - * @param {Object} attributes The initial set of data to store in the object. - * @param {Object} options The options for this object instance. - */ - -var ParseObject = function () { - /** - * The ID of this object, unique within its class. - * @property id - * @type String - */ - function ParseObject(className, attributes, options) { - (0, _classCallCheck3.default)(this, ParseObject); - - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - var toSet = null; - this._objCount = objectCount++; - if (typeof className === 'string') { - this.className = className; - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - toSet = attributes; - } - } else if (className && (typeof className === 'undefined' ? 'undefined' : (0, _typeof3.default)(className)) === 'object') { - this.className = className.className; - toSet = {}; - for (var attr in className) { - if (attr !== 'className') { - toSet[attr] = className[attr]; - } - } - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - options = attributes; - } - } - if (toSet && !this.set(toSet, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - - /** Prototype getters / setters **/ - - (0, _createClass3.default)(ParseObject, [{ - key: '_getId', - - /** Private methods **/ - - /** - * Returns a local or server Id used uniquely identify this object - */ - value: function () { - if (typeof this.id === 'string') { - return this.id; - } - if (typeof this._localId === 'string') { - return this._localId; - } - var localId = 'local' + String(localCount++); - this._localId = localId; - return localId; - } - - /** - * Returns a unique identifier used to pull data from the State Controller. - */ - - }, { - key: '_getStateIdentifier', - value: function () { - if (singleInstance) { - var _id = this.id; - if (!_id) { - _id = this._getId(); - } - return { - id: _id, - className: this.className - }; - } else { - return this; - } - } - }, { - key: '_getServerData', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return stateController.getServerData(this._getStateIdentifier()); - } - }, { - key: '_clearServerData', - value: function () { - var serverData = this._getServerData(); - var unset = {}; - for (var attr in serverData) { - unset[attr] = undefined; - } - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.setServerData(this._getStateIdentifier(), unset); - } - }, { - key: '_getPendingOps', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return stateController.getPendingOps(this._getStateIdentifier()); - } - }, { - key: '_clearPendingOps', - value: function () { - var pending = this._getPendingOps(); - var latest = pending[pending.length - 1]; - var keys = (0, _keys2.default)(latest); - keys.forEach(function (key) { - delete latest[key]; - }); - } - }, { - key: '_getDirtyObjectAttributes', - value: function () { - var attributes = this.attributes; - var stateController = _CoreManager2.default.getObjectStateController(); - var objectCache = stateController.getObjectCache(this._getStateIdentifier()); - var dirty = {}; - for (var attr in attributes) { - var val = attributes[attr]; - if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof ParseObject) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { - // Due to the way browsers construct maps, the key order will not change - // unless the object is changed - try { - var json = (0, _encode2.default)(val, false, true); - var stringified = (0, _stringify2.default)(json); - if (objectCache[attr] !== stringified) { - dirty[attr] = val; - } - } catch (e) { - // Error occurred, possibly by a nested unsaved pointer in a mutable container - // No matter how it happened, it indicates a change in the attribute - dirty[attr] = val; - } - } - } - return dirty; - } - }, { - key: '_toFullJSON', - value: function (seen) { - var json = this.toJSON(seen); - json.__type = 'Object'; - json.className = this.className; - return json; - } - }, { - key: '_getSaveJSON', - value: function () { - var pending = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - var json = {}; - - for (var attr in dirtyObjects) { - json[attr] = new _ParseOp.SetOp(dirtyObjects[attr]).toJSON(); - } - for (attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - return json; - } - }, { - key: '_getSaveParams', - value: function () { - var method = this.id ? 'PUT' : 'POST'; - var body = this._getSaveJSON(); - var path = 'classes/' + this.className; - if (this.id) { - path += '/' + this.id; - } else if (this.className === '_User') { - path = 'users'; - } - return { - method: method, - body: body, - path: path - }; - } - }, { - key: '_finishFetch', - value: function (serverData) { - if (!this.id && serverData.objectId) { - this.id = serverData.objectId; - } - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.initializeState(this._getStateIdentifier()); - var decoded = {}; - for (var attr in serverData) { - if (attr === 'ACL') { - decoded[attr] = new _ParseACL2.default(serverData[attr]); - } else if (attr !== 'objectId') { - decoded[attr] = (0, _decode2.default)(serverData[attr]); - if (decoded[attr] instanceof _ParseRelation2.default) { - decoded[attr]._ensureParentAndKey(this, attr); - } - } - } - if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = (0, _parseDate2.default)(decoded.createdAt); - } - if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = (0, _parseDate2.default)(decoded.updatedAt); - } - if (!decoded.updatedAt && decoded.createdAt) { - decoded.updatedAt = decoded.createdAt; - } - stateController.commitServerChanges(this._getStateIdentifier(), decoded); - } - }, { - key: '_setExisted', - value: function (existed) { - var stateController = _CoreManager2.default.getObjectStateController(); - var state = stateController.getState(this._getStateIdentifier()); - if (state) { - state.existed = existed; - } - } - }, { - key: '_migrateId', - value: function (serverId) { - if (this._localId && serverId) { - if (singleInstance) { - var stateController = _CoreManager2.default.getObjectStateController(); - var oldState = stateController.removeState(this._getStateIdentifier()); - this.id = serverId; - delete this._localId; - if (oldState) { - stateController.initializeState(this._getStateIdentifier(), oldState); - } - } else { - this.id = serverId; - delete this._localId; - } - } - } - }, { - key: '_handleSaveResponse', - value: function (response, status) { - var changes = {}; - - var stateController = _CoreManager2.default.getObjectStateController(); - var pending = stateController.popPendingState(this._getStateIdentifier()); - for (var attr in pending) { - if (pending[attr] instanceof _ParseOp.RelationOp) { - changes[attr] = pending[attr].applyTo(undefined, this, attr); - } else if (!(attr in response)) { - // Only SetOps and UnsetOps should not come back with results - changes[attr] = pending[attr].applyTo(undefined); - } - } - for (attr in response) { - if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { - changes[attr] = (0, _parseDate2.default)(response[attr]); - } else if (attr === 'ACL') { - changes[attr] = new _ParseACL2.default(response[attr]); - } else if (attr !== 'objectId') { - changes[attr] = (0, _decode2.default)(response[attr]); - if (changes[attr] instanceof _ParseOp.UnsetOp) { - changes[attr] = undefined; - } - } - } - if (changes.createdAt && !changes.updatedAt) { - changes.updatedAt = changes.createdAt; - } - - this._migrateId(response.objectId); - - if (status !== 201) { - this._setExisted(true); - } - - stateController.commitServerChanges(this._getStateIdentifier(), changes); - } - }, { - key: '_handleSaveError', - value: function () { - this._getPendingOps(); - - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.mergeFirstPendingState(this._getStateIdentifier()); - } - - /** Public methods **/ - - }, { - key: 'initialize', - value: function () {} - // NOOP - - - /** - * Returns a JSON version of the object suitable for saving to Parse. - * @method toJSON - * @return {Object} - */ - - }, { - key: 'toJSON', - value: function (seen) { - var seenEntry = this.id ? this.className + ':' + this.id : this; - var seen = seen || [seenEntry]; - var json = {}; - var attrs = this.attributes; - for (var attr in attrs) { - if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { - json[attr] = attrs[attr].toJSON(); - } else { - json[attr] = (0, _encode2.default)(attrs[attr], false, false, seen); - } - } - var pending = this._getPendingOps(); - for (var attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - - if (this.id) { - json.objectId = this.id; - } - return json; - } - - /** - * Determines whether this ParseObject is equal to another ParseObject - * @method equals - * @return {Boolean} - */ - - }, { - key: 'equals', - value: function (other) { - if (this === other) { - return true; - } - return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; - } - - /** - * Returns true if this object has been modified since its last - * save/refresh. If an attribute is specified, it returns true only if that - * particular attribute has been modified since the last save/refresh. - * @method dirty - * @param {String} attr An attribute name (optional). - * @return {Boolean} - */ - - }, { - key: 'dirty', - value: function (attr) { - if (!this.id) { - return true; - } - var pendingOps = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - if (attr) { - if (dirtyObjects.hasOwnProperty(attr)) { - return true; - } - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i].hasOwnProperty(attr)) { - return true; - } - } - return false; - } - if ((0, _keys2.default)(pendingOps[0]).length !== 0) { - return true; - } - if ((0, _keys2.default)(dirtyObjects).length !== 0) { - return true; - } - return false; - } - - /** - * Returns an array of keys that have been modified since last save/refresh - * @method dirtyKeys - * @return {Array of string} - */ - - }, { - key: 'dirtyKeys', - value: function () { - var pendingOps = this._getPendingOps(); - var keys = {}; - for (var i = 0; i < pendingOps.length; i++) { - for (var attr in pendingOps[i]) { - keys[attr] = true; - } - } - var dirtyObjects = this._getDirtyObjectAttributes(); - for (var attr in dirtyObjects) { - keys[attr] = true; - } - return (0, _keys2.default)(keys); - } - - /** - * Gets a Pointer referencing this Object. - * @method toPointer - * @return {Object} - */ - - }, { - key: 'toPointer', - value: function () { - if (!this.id) { - throw new Error('Cannot create a pointer to an unsaved ParseObject'); - } - return { - __type: 'Pointer', - className: this.className, - objectId: this.id - }; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'get', - value: function (attr) { - return this.attributes[attr]; - } - - /** - * Gets a relation on the given class for the attribute. - * @method relation - * @param String attr The attribute to get the relation for. - */ - - }, { - key: 'relation', - value: function (attr) { - var value = this.get(attr); - if (value) { - if (!(value instanceof _ParseRelation2.default)) { - throw new Error('Called relation() on non-relation field ' + attr); - } - value._ensureParentAndKey(this, attr); - return value; - } - return new _ParseRelation2.default(this, attr); - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'escape', - value: function (attr) { - var val = this.attributes[attr]; - if (val == null) { - return ''; - } - - if (typeof val !== 'string') { - if (typeof val.toString !== 'function') { - return ''; - } - val = val.toString(); - } - return (0, _escape3.default)(val); - } - - /** - * Returns true if the attribute contains a value that is not - * null or undefined. - * @method has - * @param {String} attr The string name of the attribute. - * @return {Boolean} - */ - - }, { - key: 'has', - value: function (attr) { - var attributes = this.attributes; - if (attributes.hasOwnProperty(attr)) { - return attributes[attr] != null; - } - return false; - } - - /** - * Sets a hash of model attributes on the object. - * - *

                  You can call it with an object containing keys and values, or with one - * key and value. For example:

                  -     *   gameTurn.set({
                  -     *     player: player1,
                  -     *     diceRoll: 2
                  -     *   }, {
                  -     *     error: function(gameTurnAgain, error) {
                  -     *       // The set failed validation.
                  -     *     }
                  -     *   });
                  -     *
                  -     *   game.set("currentPlayer", player2, {
                  -     *     error: function(gameTurnAgain, error) {
                  -     *       // The set failed validation.
                  -     *     }
                  -     *   });
                  -     *
                  -     *   game.set("finished", true);

                  - * - * @method set - * @param {String} key The key to set. - * @param {} value The value to give it. - * @param {Object} options A set of options for the set. - * The only supported option is error. - * @return {Boolean} true if the set succeeded. - */ - - }, { - key: 'set', - value: function (key, value, options) { - var changes = {}; - var newOps = {}; - if (key && (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'object') { - changes = key; - options = value; - } else if (typeof key === 'string') { - changes[key] = value; - } else { - return this; - } - - options = options || {}; - var readonly = []; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var k in changes) { - if (k === 'createdAt' || k === 'updatedAt') { - // This property is read-only, but for legacy reasons we silently - // ignore it - continue; - } - if (readonly.indexOf(k) > -1) { - throw new Error('Cannot modify readonly attribute: ' + k); - } - if (options.unset) { - newOps[k] = new _ParseOp.UnsetOp(); - } else if (changes[k] instanceof _ParseOp.Op) { - newOps[k] = changes[k]; - } else if (changes[k] && (0, _typeof3.default)(changes[k]) === 'object' && typeof changes[k].__op === 'string') { - newOps[k] = (0, _ParseOp.opFromJSON)(changes[k]); - } else if (k === 'objectId' || k === 'id') { - if (typeof changes[k] === 'string') { - this.id = changes[k]; - } - } else if (k === 'ACL' && (0, _typeof3.default)(changes[k]) === 'object' && !(changes[k] instanceof _ParseACL2.default)) { - newOps[k] = new _ParseOp.SetOp(new _ParseACL2.default(changes[k])); - } else { - newOps[k] = new _ParseOp.SetOp(changes[k]); - } - } - - // Calculate new values - var currentAttributes = this.attributes; - var newValues = {}; - for (var attr in newOps) { - if (newOps[attr] instanceof _ParseOp.RelationOp) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); - } else if (!(newOps[attr] instanceof _ParseOp.UnsetOp)) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); - } - } - - // Validate changes - if (!options.ignoreValidation) { - var validation = this.validate(newValues); - if (validation) { - if (typeof options.error === 'function') { - options.error(this, validation); - } - return false; - } - } - - // Consolidate Ops - var pendingOps = this._getPendingOps(); - var last = pendingOps.length - 1; - var stateController = _CoreManager2.default.getObjectStateController(); - for (var attr in newOps) { - var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); - stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); - } - - return this; - } - - /** - * Remove an attribute from the model. This is a noop if the attribute doesn't - * exist. - * @method unset - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'unset', - value: function (attr, options) { - options = options || {}; - options.unset = true; - return this.set(attr, null, options); - } - - /** - * Atomically increments the value of the given attribute the next time the - * object is saved. If no amount is specified, 1 is used by default. - * - * @method increment - * @param attr {String} The key. - * @param amount {Number} The amount to increment by (optional). - */ - - }, { - key: 'increment', - value: function (attr, amount) { - if (typeof amount === 'undefined') { - amount = 1; - } - if (typeof amount !== 'number') { - throw new Error('Cannot increment by a non-numeric amount.'); - } - return this.set(attr, new _ParseOp.IncrementOp(amount)); - } - - /** - * Atomically add an object to the end of the array associated with a given - * key. - * @method add - * @param attr {String} The key. - * @param item {} The item to add. - */ - - }, { - key: 'add', - value: function (attr, item) { - return this.set(attr, new _ParseOp.AddOp([item])); - } - - /** - * Atomically add an object to the array associated with a given key, only - * if it is not already present in the array. The position of the insert is - * not guaranteed. - * - * @method addUnique - * @param attr {String} The key. - * @param item {} The object to add. - */ - - }, { - key: 'addUnique', - value: function (attr, item) { - return this.set(attr, new _ParseOp.AddUniqueOp([item])); - } - - /** - * Atomically remove all instances of an object from the array associated - * with a given key. - * - * @method remove - * @param attr {String} The key. - * @param item {} The object to remove. - */ - - }, { - key: 'remove', - value: function (attr, item) { - return this.set(attr, new _ParseOp.RemoveOp([item])); - } - - /** - * Returns an instance of a subclass of Parse.Op describing what kind of - * modification has been performed on this field since the last time it was - * saved. For example, after calling object.increment("x"), calling - * object.op("x") would return an instance of Parse.Op.Increment. - * - * @method op - * @param attr {String} The key. - * @returns {Parse.Op} The operation, or undefined if none. - */ - - }, { - key: 'op', - value: function (attr) { - var pending = this._getPendingOps(); - for (var i = pending.length; i--;) { - if (pending[i][attr]) { - return pending[i][attr]; - } - } - } - - /** - * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() - * @method clone - * @return {Parse.Object} - */ - - }, { - key: 'clone', - value: function () { - var clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - var attributes = this.attributes; - if (typeof this.constructor.readOnlyAttributes === 'function') { - var readonly = this.constructor.readOnlyAttributes() || []; - // Attributes are frozen, so we have to rebuild an object, - // rather than delete readonly keys - var copy = {}; - for (var a in attributes) { - if (readonly.indexOf(a) < 0) { - copy[a] = attributes[a]; - } - } - attributes = copy; - } - if (clone.set) { - clone.set(attributes); - } - return clone; - } - - /** - * Creates a new instance of this object. Not to be confused with clone() - * @method newInstance - * @return {Parse.Object} - */ - - }, { - key: 'newInstance', - value: function () { - var clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - clone.id = this.id; - if (singleInstance) { - // Just return an object with the right id - return clone; - } - - var stateController = _CoreManager2.default.getObjectStateController(); - if (stateController) { - stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); - } - return clone; - } - - /** - * Returns true if this object has never been saved to Parse. - * @method isNew - * @return {Boolean} - */ - - }, { - key: 'isNew', - value: function () { - return !this.id; - } - - /** - * Returns true if this object was created by the Parse server when the - * object might have already been there (e.g. in the case of a Facebook - * login) - * @method existed - * @return {Boolean} - */ - - }, { - key: 'existed', - value: function () { - if (!this.id) { - return false; - } - var stateController = _CoreManager2.default.getObjectStateController(); - var state = stateController.getState(this._getStateIdentifier()); - if (state) { - return state.existed; - } - return false; - } - - /** - * Checks if the model is currently in a valid state. - * @method isValid - * @return {Boolean} - */ - - }, { - key: 'isValid', - value: function () { - return !this.validate(this.attributes); - } - - /** - * You should not call this function directly unless you subclass - * Parse.Object, in which case you can override this method - * to provide additional validation on set and - * save. Your implementation should return - * - * @method validate - * @param {Object} attrs The current data to validate. - * @return {} False if the data is valid. An error object otherwise. - * @see Parse.Object#set - */ - - }, { - key: 'validate', - value: function (attrs) { - if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof _ParseACL2.default)) { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'ACL must be a Parse ACL.'); - } - for (var key in attrs) { - if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { - return new _ParseError2.default(_ParseError2.default.INVALID_KEY_NAME); - } - } - return false; - } - - /** - * Returns the ACL for this object. - * @method getACL - * @returns {Parse.ACL} An instance of Parse.ACL. - * @see Parse.Object#get - */ - - }, { - key: 'getACL', - value: function () { - var acl = this.get('ACL'); - if (acl instanceof _ParseACL2.default) { - return acl; - } - return null; - } - - /** - * Sets the ACL to be used for this object. - * @method setACL - * @param {Parse.ACL} acl An instance of Parse.ACL. - * @param {Object} options Optional Backbone-like options object to be - * passed in to set. - * @return {Boolean} Whether the set passed validation. - * @see Parse.Object#set - */ - - }, { - key: 'setACL', - value: function (acl, options) { - return this.set('ACL', acl, options); - } - - /** - * Clears any changes to this object made since the last call to save() - * @method revert - */ - - }, { - key: 'revert', - value: function () { - this._clearPendingOps(); - } - - /** - * Clears all attributes on a model - * @method clear - */ - - }, { - key: 'clear', - value: function () { - var attributes = this.attributes; - var erasable = {}; - var readonly = ['createdAt', 'updatedAt']; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var attr in attributes) { - if (readonly.indexOf(attr) < 0) { - erasable[attr] = true; - } - } - return this.set(erasable, { unset: true }); - } - - /** - * Fetch the model from the server. If the server's representation of the - * model differs from its current attributes, they will be overriden. - * - * @method fetch - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                    - *
                  • success: A Backbone-style success callback. - *
                  • error: An Backbone-style error callback. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * @return {Parse.Promise} A promise that is fulfilled when the fetch - * completes. - */ - - }, { - key: 'fetch', - value: function (options) { - options = options || {}; - var fetchOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - fetchOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - fetchOptions.sessionToken = options.sessionToken; - } - var controller = _CoreManager2.default.getObjectController(); - return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); - } - - /** - * Set a hash of model attributes, and save the model to the server. - * updatedAt will be updated when the request returns. - * You can either call it as:
                  -     *   object.save();
                  - * or
                  -     *   object.save(null, options);
                  - * or
                  -     *   object.save(attrs, options);
                  - * or
                  -     *   object.save(key, value, options);
                  - * - * For example,
                  -     *   gameTurn.save({
                  -     *     player: "Jake Cutter",
                  -     *     diceRoll: 2
                  -     *   }, {
                  -     *     success: function(gameTurnAgain) {
                  -     *       // The save was successful.
                  -     *     },
                  -     *     error: function(gameTurnAgain, error) {
                  -     *       // The save failed.  Error is an instance of Parse.Error.
                  -     *     }
                  -     *   });
                  - * or with promises:
                  -     *   gameTurn.save({
                  -     *     player: "Jake Cutter",
                  -     *     diceRoll: 2
                  -     *   }).then(function(gameTurnAgain) {
                  -     *     // The save was successful.
                  -     *   }, function(error) {
                  -     *     // The save failed.  Error is an instance of Parse.Error.
                  -     *   });
                  - * - * @method save - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                    - *
                  • success: A Backbone-style success callback. - *
                  • error: An Backbone-style error callback. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * @return {Parse.Promise} A promise that is fulfilled when the save - * completes. - */ - - }, { - key: 'save', - value: function (arg1, arg2, arg3) { - var _this = this; - - var attrs; - var options; - if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object' || typeof arg1 === 'undefined') { - attrs = arg1; - if ((typeof arg2 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg2)) === 'object') { - options = arg2; - } - } else { - attrs = {}; - attrs[arg1] = arg2; - options = arg3; - } - - // Support save({ success: function() {}, error: function() {} }) - if (!options && attrs) { - options = {}; - if (typeof attrs.success === 'function') { - options.success = attrs.success; - delete attrs.success; - } - if (typeof attrs.error === 'function') { - options.error = attrs.error; - delete attrs.error; - } - } - - if (attrs) { - var validation = this.validate(attrs); - if (validation) { - if (options && typeof options.error === 'function') { - options.error(this, validation); - } - return _ParsePromise2.default.error(validation); - } - this.set(attrs, options); - } - - options = options || {}; - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = !!options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { - saveOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getObjectController(); - var unsaved = (0, _unsavedChildren2.default)(this); - return controller.save(unsaved, saveOptions).then(function () { - return controller.save(_this, saveOptions); - })._thenRunCallbacks(options, this); - } - - /** - * Destroy this model on the server if it was already persisted. - * If `wait: true` is passed, waits for the server to respond - * before removal. - * - * @method destroy - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                    - *
                  • success: A Backbone-style success callback - *
                  • error: An Backbone-style error callback. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * @return {Parse.Promise} A promise that is fulfilled when the destroy - * completes. - */ - - }, { - key: 'destroy', - value: function (options) { - options = options || {}; - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - if (!this.id) { - return _ParsePromise2.default.as()._thenRunCallbacks(options); - } - return _CoreManager2.default.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); - } - - /** Static methods **/ - - }, { - key: 'attributes', - get: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return (0, _freeze2.default)(stateController.estimateAttributes(this._getStateIdentifier())); - } - - /** - * The first time this object was saved on the server. - * @property createdAt - * @type Date - */ - - }, { - key: 'createdAt', - get: function () { - return this._getServerData().createdAt; - } - - /** - * The last time this object was updated on the server. - * @property updatedAt - * @type Date - */ - - }, { - key: 'updatedAt', - get: function () { - return this._getServerData().updatedAt; - } - }], [{ - key: '_clearAllState', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.clearAllState(); - } - - /** - * Fetches the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                  -     *   Parse.Object.fetchAll([object1, object2, ...], {
                  -     *     success: function(list) {
                  -     *       // All the objects were fetched.
                  -     *     },
                  -     *     error: function(error) {
                  -     *       // An error occurred while fetching one of the objects.
                  -     *     },
                  -     *   });
                  -     * 
                  - * - * @method fetchAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                    - *
                  • success: A Backbone-style success callback. - *
                  • error: An Backbone-style error callback. - *
                  - */ - - }, { - key: 'fetchAll', - value: function (list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); - } - - /** - * Fetches the given list of Parse.Object if needed. - * If any error is encountered, stops and calls the error handler. - * - *
                  -     *   Parse.Object.fetchAllIfNeeded([object1, ...], {
                  -     *     success: function(list) {
                  -     *       // Objects were fetched and updated.
                  -     *     },
                  -     *     error: function(error) {
                  -     *       // An error occurred while fetching one of the objects.
                  -     *     },
                  -     *   });
                  -     * 
                  - * - * @method fetchAllIfNeeded - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                    - *
                  • success: A Backbone-style success callback. - *
                  • error: An Backbone-style error callback. - *
                  - */ - - }, { - key: 'fetchAllIfNeeded', - value: function (list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); - } - - /** - * Destroy the given list of models on the server if it was already persisted. - * - *

                  Unlike saveAll, if an error occurs while deleting an individual model, - * this method will continue trying to delete the rest of the models if - * possible, except in the case of a fatal error like a connection error. - * - *

                  In particular, the Parse.Error object returned in the case of error may - * be one of two types: - * - *

                    - *
                  • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an - * array of other Parse.Error objects. Each error object in this array - * has an "object" property that references the object that could not be - * deleted (for instance, because that object could not be found).
                  • - *
                  • A non-aggregate Parse.Error. This indicates a serious error that - * caused the delete operation to be aborted partway through (for - * instance, a connection failure in the middle of the delete).
                  • - *
                  - * - *
                  -     *   Parse.Object.destroyAll([object1, object2, ...], {
                  -     *     success: function() {
                  -     *       // All the objects were deleted.
                  -     *     },
                  -     *     error: function(error) {
                  -     *       // An error occurred while deleting one or more of the objects.
                  -     *       // If this is an aggregate error, then we can inspect each error
                  -     *       // object individually to determine the reason why a particular
                  -     *       // object was not deleted.
                  -     *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
                  -     *         for (var i = 0; i < error.errors.length; i++) {
                  -     *           console.log("Couldn't delete " + error.errors[i].object.id +
                  -     *             "due to " + error.errors[i].message);
                  -     *         }
                  -     *       } else {
                  -     *         console.log("Delete aborted because of " + error.message);
                  -     *       }
                  -     *     },
                  -     *   });
                  -     * 
                  - * - * @method destroyAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                    - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * @return {Parse.Promise} A promise that is fulfilled when the destroyAll - * completes. - */ - - }, { - key: 'destroyAll', - value: function (list, options) { - var options = options || {}; - - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); - } - - /** - * Saves the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                  -     *   Parse.Object.saveAll([object1, object2, ...], {
                  -     *     success: function(list) {
                  -     *       // All the objects were saved.
                  -     *     },
                  -     *     error: function(error) {
                  -     *       // An error occurred while saving one of the objects.
                  -     *     },
                  -     *   });
                  -     * 
                  - * - * @method saveAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                    - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - */ - - }, { - key: 'saveAll', - value: function (list, options) { - var options = options || {}; - - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - saveOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); - } - - /** - * Creates a reference to a subclass of Parse.Object with the given id. This - * does not exist on Parse.Object, only on subclasses. - * - *

                  A shortcut for:

                  -     *  var Foo = Parse.Object.extend("Foo");
                  -     *  var pointerToFoo = new Foo();
                  -     *  pointerToFoo.id = "myObjectId";
                  -     * 
                  - * - * @method createWithoutData - * @param {String} id The ID of the object to create a reference to. - * @static - * @return {Parse.Object} A Parse.Object reference. - */ - - }, { - key: 'createWithoutData', - value: function (id) { - var obj = new this(); - obj.id = id; - return obj; - } - - /** - * Creates a new instance of a Parse Object from a JSON representation. - * @method fromJSON - * @param {Object} json The JSON map of the Object's data - * @param {boolean} override In single instance mode, all old server data - * is overwritten if this is set to true - * @static - * @return {Parse.Object} A Parse.Object reference - */ - - }, { - key: 'fromJSON', - value: function (json, override) { - if (!json.className) { - throw new Error('Cannot create an object without a className'); - } - var constructor = classMap[json.className]; - var o = constructor ? new constructor() : new ParseObject(json.className); - var otherAttributes = {}; - for (var attr in json) { - if (attr !== 'className' && attr !== '__type') { - otherAttributes[attr] = json[attr]; - } - } - if (override) { - // id needs to be set before clearServerData can work - if (otherAttributes.objectId) { - o.id = otherAttributes.objectId; - } - var preserved = null; - if (typeof o._preserveFieldsOnFetch === 'function') { - preserved = o._preserveFieldsOnFetch(); - } - o._clearServerData(); - if (preserved) { - o._finishFetch(preserved); - } - } - o._finishFetch(otherAttributes); - if (json.objectId) { - o._setExisted(true); - } - return o; - } - - /** - * Registers a subclass of Parse.Object with a specific class name. - * When objects of that class are retrieved from a query, they will be - * instantiated with this subclass. - * This is only necessary when using ES6 subclassing. - * @method registerSubclass - * @param {String} className The class name of the subclass - * @param {Class} constructor The subclass - */ - - }, { - key: 'registerSubclass', - value: function (className, constructor) { - if (typeof className !== 'string') { - throw new TypeError('The first argument must be a valid class name.'); - } - if (typeof constructor === 'undefined') { - throw new TypeError('You must supply a subclass constructor.'); - } - if (typeof constructor !== 'function') { - throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); - } - classMap[className] = constructor; - if (!constructor.className) { - constructor.className = className; - } - } - - /** - * Creates a new subclass of Parse.Object for the given Parse class name. - * - *

                  Every extension of a Parse class will inherit from the most recent - * previous extension of that class. When a Parse.Object is automatically - * created by parsing JSON, it will use the most recent extension of that - * class.

                  - * - *

                  You should call either:

                  -     *     var MyClass = Parse.Object.extend("MyClass", {
                  -     *         Instance methods,
                  -     *         initialize: function(attrs, options) {
                  -     *             this.someInstanceProperty = [],
                  -     *             Other instance properties
                  -     *         }
                  -     *     }, {
                  -     *         Class properties
                  -     *     });
                  - * or, for Backbone compatibility:
                  -     *     var MyClass = Parse.Object.extend({
                  -     *         className: "MyClass",
                  -     *         Instance methods,
                  -     *         initialize: function(attrs, options) {
                  -     *             this.someInstanceProperty = [],
                  -     *             Other instance properties
                  -     *         }
                  -     *     }, {
                  -     *         Class properties
                  -     *     });

                  - * - * @method extend - * @param {String} className The name of the Parse class backing this model. - * @param {Object} protoProps Instance properties to add to instances of the - * class returned from this method. - * @param {Object} classProps Class properties to add the class returned from - * this method. - * @return {Class} A new subclass of Parse.Object. - */ - - }, { - key: 'extend', - value: function (className, protoProps, classProps) { - if (typeof className !== 'string') { - if (className && typeof className.className === 'string') { - return ParseObject.extend(className.className, className, protoProps); - } else { - throw new Error('Parse.Object.extend\'s first argument should be the className.'); - } - } - var adjustedClassName = className; - - if (adjustedClassName === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { - adjustedClassName = '_User'; - } - - var parentProto = ParseObject.prototype; - if (this.hasOwnProperty('__super__') && this.__super__) { - parentProto = this.prototype; - } else if (classMap[adjustedClassName]) { - parentProto = classMap[adjustedClassName].prototype; - } - var ParseObjectSubclass = function (attributes, options) { - this.className = adjustedClassName; - this._objCount = objectCount++; - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!this.set(attributes || {}, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - }; - ParseObjectSubclass.className = adjustedClassName; - ParseObjectSubclass.__super__ = parentProto; - - ParseObjectSubclass.prototype = (0, _create2.default)(parentProto, { - constructor: { - value: ParseObjectSubclass, - enumerable: false, - writable: true, - configurable: true - } - }); - - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseObjectSubclass.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseObjectSubclass, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - ParseObjectSubclass.extend = function (name, protoProps, classProps) { - if (typeof name === 'string') { - return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); - } - return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); - }; - ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; - - classMap[adjustedClassName] = ParseObjectSubclass; - return ParseObjectSubclass; - } - - /** - * Enable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * This is disabled by default in server environments, since it can lead to - * security issues. - * @method enableSingleInstance - */ - - }, { - key: 'enableSingleInstance', - value: function () { - singleInstance = true; - _CoreManager2.default.setObjectStateController(SingleInstanceStateController); - } - - /** - * Disable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * When disabled, you can have two instances of the same object in memory - * without them sharing attributes. - * @method disableSingleInstance - */ - - }, { - key: 'disableSingleInstance', - value: function () { - singleInstance = false; - _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); - } - }]); - return ParseObject; -}(); - -exports.default = ParseObject; - -var DefaultController = { - fetch: function (target, forceFetch, options) { - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - var objs = []; - var ids = []; - var className = null; - var results = []; - var error = null; - target.forEach(function (el, i) { - if (error) { - return; - } - if (!className) { - className = el.className; - } - if (className !== el.className) { - error = new _ParseError2.default(_ParseError2.default.INVALID_CLASS_NAME, 'All objects should be of the same class'); - } - if (!el.id) { - error = new _ParseError2.default(_ParseError2.default.MISSING_OBJECT_ID, 'All objects must have an ID'); - } - if (forceFetch || (0, _keys2.default)(el._getServerData()).length === 0) { - ids.push(el.id); - objs.push(el); - } - results.push(el); - }); - if (error) { - return _ParsePromise2.default.error(error); - } - var query = new _ParseQuery2.default(className); - query.containedIn('objectId', ids); - query._limit = ids.length; - return query.find(options).then(function (objects) { - var idMap = {}; - objects.forEach(function (o) { - idMap[o.id] = o; - }); - for (var i = 0; i < objs.length; i++) { - var obj = objs[i]; - if (!obj || !obj.id || !idMap[obj.id]) { - if (forceFetch) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); - } - } - } - if (!singleInstance) { - // If single instance objects are disabled, we need to replace the - for (var i = 0; i < results.length; i++) { - var obj = results[i]; - if (obj && obj.id && idMap[obj.id]) { - var id = obj.id; - obj._finishFetch(idMap[id].toJSON()); - results[i] = idMap[id]; - } - } - } - return _ParsePromise2.default.as(results); - }); - } else { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function (response, status, xhr) { - if (target instanceof ParseObject) { - target._clearPendingOps(); - target._clearServerData(); - target._finishFetch(response); - } - return target; - }); - } - }, - destroy: function (target, options) { - var RESTController = _CoreManager2.default.getRESTController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - var batches = [[]]; - target.forEach(function (obj) { - if (!obj.id) { - return; - } - batches[batches.length - 1].push(obj); - if (batches[batches.length - 1].length >= 20) { - batches.push([]); - } - }); - if (batches[batches.length - 1].length === 0) { - // If the last batch is empty, remove it - batches.pop(); - } - var deleteCompleted = _ParsePromise2.default.as(); - var errors = []; - batches.forEach(function (batch) { - deleteCompleted = deleteCompleted.then(function () { - return RESTController.request('POST', 'batch', { - requests: batch.map(function (obj) { - return { - method: 'DELETE', - path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), - body: {} - }; - }) - }, options).then(function (results) { - for (var i = 0; i < results.length; i++) { - if (results[i] && results[i].hasOwnProperty('error')) { - var err = new _ParseError2.default(results[i].error.code, results[i].error.error); - err.object = batch[i]; - errors.push(err); - } - } - }); - }); - }); - return deleteCompleted.then(function () { - if (errors.length) { - var aggregate = new _ParseError2.default(_ParseError2.default.AGGREGATE_ERROR); - aggregate.errors = errors; - return _ParsePromise2.default.error(aggregate); - } - return _ParsePromise2.default.as(target); - }); - } else if (target instanceof ParseObject) { - return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function () { - return _ParsePromise2.default.as(target); - }); - } - return _ParsePromise2.default.as(target); - }, - save: function (target, options) { - var RESTController = _CoreManager2.default.getRESTController(); - var stateController = _CoreManager2.default.getObjectStateController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - - var unsaved = target.concat(); - for (var i = 0; i < target.length; i++) { - if (target[i] instanceof ParseObject) { - unsaved = unsaved.concat((0, _unsavedChildren2.default)(target[i], true)); - } - } - unsaved = (0, _unique2.default)(unsaved); - - var filesSaved = _ParsePromise2.default.as(); - var pending = []; - unsaved.forEach(function (el) { - if (el instanceof _ParseFile2.default) { - filesSaved = filesSaved.then(function () { - return el.save(); - }); - } else if (el instanceof ParseObject) { - pending.push(el); - } - }); - - return filesSaved.then(function () { - var objectError = null; - return _ParsePromise2.default._continueWhile(function () { - return pending.length > 0; - }, function () { - var batch = []; - var nextPending = []; - pending.forEach(function (el) { - if (batch.length < 20 && (0, _canBeSerialized2.default)(el)) { - batch.push(el); - } else { - nextPending.push(el); - } - }); - pending = nextPending; - if (batch.length < 1) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); - } - - // Queue up tasks for each object in the batch. - // When every task is ready, the API request will execute - var batchReturned = new _ParsePromise2.default(); - var batchReady = []; - var batchTasks = []; - batch.forEach(function (obj, index) { - var ready = new _ParsePromise2.default(); - batchReady.push(ready); - - stateController.pushPendingState(obj._getStateIdentifier()); - batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { - ready.resolve(); - return batchReturned.then(function (responses, status) { - if (responses[index].hasOwnProperty('success')) { - obj._handleSaveResponse(responses[index].success, status); - } else { - if (!objectError && responses[index].hasOwnProperty('error')) { - var serverError = responses[index].error; - objectError = new _ParseError2.default(serverError.code, serverError.error); - // Cancel the rest of the save - pending = []; - } - obj._handleSaveError(); - } - }); - })); - }); - - _ParsePromise2.default.when(batchReady).then(function () { - // Kick off the batch request - return RESTController.request('POST', 'batch', { - requests: batch.map(function (obj) { - var params = obj._getSaveParams(); - params.path = getServerUrlPath() + params.path; - return params; - }) - }, options); - }).then(function (response, status, xhr) { - batchReturned.resolve(response, status); - }); - - return _ParsePromise2.default.when(batchTasks); - }).then(function () { - if (objectError) { - return _ParsePromise2.default.error(objectError); - } - return _ParsePromise2.default.as(target); - }); - }); - } else if (target instanceof ParseObject) { - // copying target lets Flow guarantee the pointer isn't modified elsewhere - var targetCopy = target; - var task = function () { - var params = targetCopy._getSaveParams(); - return RESTController.request(params.method, params.path, params.body, options).then(function (response, status) { - targetCopy._handleSaveResponse(response, status); - }, function (error) { - targetCopy._handleSaveError(); - return _ParsePromise2.default.error(error); - }); - }; - - stateController.pushPendingState(target._getStateIdentifier()); - return stateController.enqueueTask(target._getStateIdentifier(), task).then(function () { - return target; - }, function (error) { - return _ParsePromise2.default.error(error); - }); - } - return _ParsePromise2.default.as(); - } -}; - -_CoreManager2.default.setObjectController(DefaultController); -},{"./CoreManager":3,"./ParseACL":11,"./ParseError":13,"./ParseFile":14,"./ParseOp":19,"./ParsePromise":20,"./ParseQuery":21,"./ParseRelation":22,"./SingleInstanceStateController":28,"./UniqueInstanceStateController":32,"./canBeSerialized":34,"./decode":35,"./encode":36,"./equals":37,"./escape":38,"./parseDate":40,"./unique":41,"./unsavedChildren":42,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/object/create":46,"babel-runtime/core-js/object/define-property":47,"babel-runtime/core-js/object/freeze":48,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],19:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.RelationOp = exports.RemoveOp = exports.AddUniqueOp = exports.AddOp = exports.IncrementOp = exports.UnsetOp = exports.SetOp = exports.Op = undefined; - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -exports.opFromJSON = opFromJSON; - -var _arrayContainsObject = _dereq_('./arrayContainsObject'); - -var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); - -var _decode = _dereq_('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _unique = _dereq_('./unique'); - -var _unique2 = _interopRequireDefault(_unique); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function opFromJSON(json) { - if (!json || !json.__op) { - return null; - } - switch (json.__op) { - case 'Delete': - return new UnsetOp(); - case 'Increment': - return new IncrementOp(json.amount); - case 'Add': - return new AddOp((0, _decode2.default)(json.objects)); - case 'AddUnique': - return new AddUniqueOp((0, _decode2.default)(json.objects)); - case 'Remove': - return new RemoveOp((0, _decode2.default)(json.objects)); - case 'AddRelation': - var toAdd = (0, _decode2.default)(json.objects); - if (!Array.isArray(toAdd)) { - return new RelationOp([], []); - } - return new RelationOp(toAdd, []); - case 'RemoveRelation': - var toRemove = (0, _decode2.default)(json.objects); - if (!Array.isArray(toRemove)) { - return new RelationOp([], []); - } - return new RelationOp([], toRemove); - case 'Batch': - var toAdd = []; - var toRemove = []; - for (var i = 0; i < json.ops.length; i++) { - if (json.ops[i].__op === 'AddRelation') { - toAdd = toAdd.concat((0, _decode2.default)(json.ops[i].objects)); - } else if (json.ops[i].__op === 'RemoveRelation') { - toRemove = toRemove.concat((0, _decode2.default)(json.ops[i].objects)); - } - } - return new RelationOp(toAdd, toRemove); - } - return null; -} - -var Op = exports.Op = function () { - function Op() { - (0, _classCallCheck3.default)(this, Op); - } - - (0, _createClass3.default)(Op, [{ - key: 'applyTo', - - // Empty parent class - value: function (value) {} - }, { - key: 'mergeWith', - value: function (previous) {} - }, { - key: 'toJSON', - value: function () {} - }]); - return Op; -}(); - -var SetOp = exports.SetOp = function (_Op) { - (0, _inherits3.default)(SetOp, _Op); - - function SetOp(value) { - (0, _classCallCheck3.default)(this, SetOp); - - var _this = (0, _possibleConstructorReturn3.default)(this, (SetOp.__proto__ || (0, _getPrototypeOf2.default)(SetOp)).call(this)); - - _this._value = value; - return _this; - } - - (0, _createClass3.default)(SetOp, [{ - key: 'applyTo', - value: function (value) { - return this._value; - } - }, { - key: 'mergeWith', - value: function (previous) { - return new SetOp(this._value); - } - }, { - key: 'toJSON', - value: function () { - return (0, _encode2.default)(this._value, false, true); - } - }]); - return SetOp; -}(Op); - -var UnsetOp = exports.UnsetOp = function (_Op2) { - (0, _inherits3.default)(UnsetOp, _Op2); - - function UnsetOp() { - (0, _classCallCheck3.default)(this, UnsetOp); - return (0, _possibleConstructorReturn3.default)(this, (UnsetOp.__proto__ || (0, _getPrototypeOf2.default)(UnsetOp)).apply(this, arguments)); - } - - (0, _createClass3.default)(UnsetOp, [{ - key: 'applyTo', - value: function (value) { - return undefined; - } - }, { - key: 'mergeWith', - value: function (previous) { - return new UnsetOp(); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Delete' }; - } - }]); - return UnsetOp; -}(Op); - -var IncrementOp = exports.IncrementOp = function (_Op3) { - (0, _inherits3.default)(IncrementOp, _Op3); - - function IncrementOp(amount) { - (0, _classCallCheck3.default)(this, IncrementOp); - - var _this3 = (0, _possibleConstructorReturn3.default)(this, (IncrementOp.__proto__ || (0, _getPrototypeOf2.default)(IncrementOp)).call(this)); - - if (typeof amount !== 'number') { - throw new TypeError('Increment Op must be initialized with a numeric amount.'); - } - _this3._amount = amount; - return _this3; - } - - (0, _createClass3.default)(IncrementOp, [{ - key: 'applyTo', - value: function (value) { - if (typeof value === 'undefined') { - return this._amount; - } - if (typeof value !== 'number') { - throw new TypeError('Cannot increment a non-numeric value.'); - } - return this._amount + value; - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._amount); - } - if (previous instanceof IncrementOp) { - return new IncrementOp(this.applyTo(previous._amount)); - } - throw new Error('Cannot merge Increment Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Increment', amount: this._amount }; - } - }]); - return IncrementOp; -}(Op); - -var AddOp = exports.AddOp = function (_Op4) { - (0, _inherits3.default)(AddOp, _Op4); - - function AddOp(value) { - (0, _classCallCheck3.default)(this, AddOp); - - var _this4 = (0, _possibleConstructorReturn3.default)(this, (AddOp.__proto__ || (0, _getPrototypeOf2.default)(AddOp)).call(this)); - - _this4._value = Array.isArray(value) ? value : [value]; - return _this4; - } - - (0, _createClass3.default)(AddOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return this._value; - } - if (Array.isArray(value)) { - return value.concat(this._value); - } - throw new Error('Cannot add elements to a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddOp) { - return new AddOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge Add Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Add', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return AddOp; -}(Op); - -var AddUniqueOp = exports.AddUniqueOp = function (_Op5) { - (0, _inherits3.default)(AddUniqueOp, _Op5); - - function AddUniqueOp(value) { - (0, _classCallCheck3.default)(this, AddUniqueOp); - - var _this5 = (0, _possibleConstructorReturn3.default)(this, (AddUniqueOp.__proto__ || (0, _getPrototypeOf2.default)(AddUniqueOp)).call(this)); - - _this5._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); - return _this5; - } - - (0, _createClass3.default)(AddUniqueOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return this._value || []; - } - if (Array.isArray(value)) { - // copying value lets Flow guarantee the pointer isn't modified elsewhere - var valueCopy = value; - var toAdd = []; - this._value.forEach(function (v) { - if (v instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(valueCopy, v)) { - toAdd.push(v); - } - } else { - if (valueCopy.indexOf(v) < 0) { - toAdd.push(v); - } - } - }); - return value.concat(toAdd); - } - throw new Error('Cannot add elements to a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddUniqueOp) { - return new AddUniqueOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge AddUnique Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'AddUnique', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return AddUniqueOp; -}(Op); - -var RemoveOp = exports.RemoveOp = function (_Op6) { - (0, _inherits3.default)(RemoveOp, _Op6); - - function RemoveOp(value) { - (0, _classCallCheck3.default)(this, RemoveOp); - - var _this6 = (0, _possibleConstructorReturn3.default)(this, (RemoveOp.__proto__ || (0, _getPrototypeOf2.default)(RemoveOp)).call(this)); - - _this6._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); - return _this6; - } - - (0, _createClass3.default)(RemoveOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return []; - } - if (Array.isArray(value)) { - var i = value.indexOf(this._value); - var removed = value.concat([]); - for (var i = 0; i < this._value.length; i++) { - var index = removed.indexOf(this._value[i]); - while (index > -1) { - removed.splice(index, 1); - index = removed.indexOf(this._value[i]); - } - if (this._value[i] instanceof _ParseObject2.default && this._value[i].id) { - for (var j = 0; j < removed.length; j++) { - if (removed[j] instanceof _ParseObject2.default && this._value[i].id === removed[j].id) { - removed.splice(j, 1); - j--; - } - } - } - } - return removed; - } - throw new Error('Cannot remove elements from a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new UnsetOp(); - } - if (previous instanceof RemoveOp) { - var uniques = previous._value.concat([]); - for (var i = 0; i < this._value.length; i++) { - if (this._value[i] instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(uniques, this._value[i])) { - uniques.push(this._value[i]); - } - } else { - if (uniques.indexOf(this._value[i]) < 0) { - uniques.push(this._value[i]); - } - } - } - return new RemoveOp(uniques); - } - throw new Error('Cannot merge Remove Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Remove', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return RemoveOp; -}(Op); - -var RelationOp = exports.RelationOp = function (_Op7) { - (0, _inherits3.default)(RelationOp, _Op7); - - function RelationOp(adds, removes) { - (0, _classCallCheck3.default)(this, RelationOp); - - var _this7 = (0, _possibleConstructorReturn3.default)(this, (RelationOp.__proto__ || (0, _getPrototypeOf2.default)(RelationOp)).call(this)); - - _this7._targetClassName = null; - - if (Array.isArray(adds)) { - _this7.relationsToAdd = (0, _unique2.default)(adds.map(_this7._extractId, _this7)); - } - - if (Array.isArray(removes)) { - _this7.relationsToRemove = (0, _unique2.default)(removes.map(_this7._extractId, _this7)); - } - return _this7; - } - - (0, _createClass3.default)(RelationOp, [{ - key: '_extractId', - value: function (obj) { - if (typeof obj === 'string') { - return obj; - } - if (!obj.id) { - throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); - } - if (!this._targetClassName) { - this._targetClassName = obj.className; - } - if (this._targetClassName !== obj.className) { - throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); - } - return obj.id; - } - }, { - key: 'applyTo', - value: function (value, object, key) { - if (!value) { - if (!object || !key) { - throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); - } - var parent = new _ParseObject2.default(object.className); - if (object.id && object.id.indexOf('local') === 0) { - parent._localId = object.id; - } else if (object.id) { - parent.id = object.id; - } - var relation = new _ParseRelation2.default(parent, key); - relation.targetClassName = this._targetClassName; - return relation; - } - if (value instanceof _ParseRelation2.default) { - if (this._targetClassName) { - if (value.targetClassName) { - if (this._targetClassName !== value.targetClassName) { - throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); - } - } else { - value.targetClassName = this._targetClassName; - } - } - return value; - } else { - throw new Error('Relation cannot be applied to a non-relation field'); - } - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } else if (previous instanceof UnsetOp) { - throw new Error('You cannot modify a relation after deleting it.'); - } else if (previous instanceof RelationOp) { - if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { - throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); - } - var newAdd = previous.relationsToAdd.concat([]); - this.relationsToRemove.forEach(function (r) { - var index = newAdd.indexOf(r); - if (index > -1) { - newAdd.splice(index, 1); - } - }); - this.relationsToAdd.forEach(function (r) { - var index = newAdd.indexOf(r); - if (index < 0) { - newAdd.push(r); - } - }); - - var newRemove = previous.relationsToRemove.concat([]); - this.relationsToAdd.forEach(function (r) { - var index = newRemove.indexOf(r); - if (index > -1) { - newRemove.splice(index, 1); - } - }); - this.relationsToRemove.forEach(function (r) { - var index = newRemove.indexOf(r); - if (index < 0) { - newRemove.push(r); - } - }); - - var newRelation = new RelationOp(newAdd, newRemove); - newRelation._targetClassName = this._targetClassName; - return newRelation; - } - throw new Error('Cannot merge Relation Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - var _this8 = this; - - var idToPointer = function (id) { - return { - __type: 'Pointer', - className: _this8._targetClassName, - objectId: id - }; - }; - - var adds = null; - var removes = null; - var pointers = null; - - if (this.relationsToAdd.length > 0) { - pointers = this.relationsToAdd.map(idToPointer); - adds = { __op: 'AddRelation', objects: pointers }; - } - if (this.relationsToRemove.length > 0) { - pointers = this.relationsToRemove.map(idToPointer); - removes = { __op: 'RemoveRelation', objects: pointers }; - } - - if (adds && removes) { - return { __op: 'Batch', ops: [adds, removes] }; - } - - return adds || removes || {}; - } - }]); - return RelationOp; -}(Op); -},{"./ParseObject":18,"./ParseRelation":22,"./arrayContainsObject":33,"./decode":35,"./encode":36,"./unique":41,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],20:[function(_dereq_,module,exports){ -(function (process){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getIterator2 = _dereq_('babel-runtime/core-js/get-iterator'); - -var _getIterator3 = _interopRequireDefault(_getIterator2); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var _isPromisesAPlusCompliant = true; - -/** - * A Promise is returned by async methods as a hook to provide callbacks to be - * called when the async task is fulfilled. - * - *

                  Typical usage would be like:

                  - *    query.find().then(function(results) {
                  - *      results[0].set("foo", "bar");
                  - *      return results[0].saveAsync();
                  - *    }).then(function(result) {
                  - *      console.log("Updated " + result.id);
                  - *    });
                  - * 

                  - * - * @class Parse.Promise - * @constructor - */ - -var ParsePromise = function () { - function ParsePromise(executor) { - (0, _classCallCheck3.default)(this, ParsePromise); - - this._resolved = false; - this._rejected = false; - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - - if (typeof executor === 'function') { - executor(this.resolve.bind(this), this.reject.bind(this)); - } - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method resolve - * @param {Object} result the result to pass to the callbacks. - */ - - (0, _createClass3.default)(ParsePromise, [{ - key: 'resolve', - value: function () { - if (this._resolved || this._rejected) { - throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._resolved = true; - - for (var _len = arguments.length, results = Array(_len), _key = 0; _key < _len; _key++) { - results[_key] = arguments[_key]; - } - - this._result = results; - for (var i = 0; i < this._resolvedCallbacks.length; i++) { - this._resolvedCallbacks[i].apply(this, results); - } - - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method reject - * @param {Object} error the error to pass to the callbacks. - */ - - }, { - key: 'reject', - value: function (error) { - if (this._resolved || this._rejected) { - throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._rejected = true; - this._error = error; - for (var i = 0; i < this._rejectedCallbacks.length; i++) { - this._rejectedCallbacks[i](error); - } - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Adds callbacks to be called when this promise is fulfilled. Returns a new - * Promise that will be fulfilled when the callback is complete. It allows - * chaining. If the callback itself returns a Promise, then the one returned - * by "then" will not be fulfilled until that one returned by the callback - * is fulfilled. - * @method then - * @param {Function} resolvedCallback Function that is called when this - * Promise is resolved. Once the callback is complete, then the Promise - * returned by "then" will also be fulfilled. - * @param {Function} rejectedCallback Function that is called when this - * Promise is rejected with an error. Once the callback is complete, then - * the promise returned by "then" with be resolved successfully. If - * rejectedCallback is null, or it returns a rejected Promise, then the - * Promise returned by "then" will be rejected with that error. - * @return {Parse.Promise} A new Promise that will be fulfilled after this - * Promise is fulfilled and either callback has completed. If the callback - * returned a Promise, then this Promise will not be fulfilled until that - * one is. - */ - - }, { - key: 'then', - value: function (resolvedCallback, rejectedCallback) { - var _this = this; - - var promise = new ParsePromise(); - - var wrappedResolvedCallback = function () { - for (var _len2 = arguments.length, results = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - results[_key2] = arguments[_key2]; - } - - if (typeof resolvedCallback === 'function') { - if (_isPromisesAPlusCompliant) { - try { - results = [resolvedCallback.apply(this, results)]; - } catch (e) { - results = [ParsePromise.error(e)]; - } - } else { - results = [resolvedCallback.apply(this, results)]; - } - } - if (results.length === 1 && ParsePromise.is(results[0])) { - results[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - promise.resolve.apply(promise, results); - } - }; - - var wrappedRejectedCallback = function (error) { - var result = []; - if (typeof rejectedCallback === 'function') { - if (_isPromisesAPlusCompliant) { - try { - result = [rejectedCallback(error)]; - } catch (e) { - result = [ParsePromise.error(e)]; - } - } else { - result = [rejectedCallback(error)]; - } - if (result.length === 1 && ParsePromise.is(result[0])) { - result[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - if (_isPromisesAPlusCompliant) { - promise.resolve.apply(promise, result); - } else { - promise.reject(result[0]); - } - } - } else { - promise.reject(error); - } - }; - - var runLater = function (fn) { - fn.call(); - }; - if (_isPromisesAPlusCompliant) { - if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { - runLater = function (fn) { - process.nextTick(fn); - }; - } else if (typeof setTimeout === 'function') { - runLater = function (fn) { - setTimeout(fn, 0); - }; - } - } - - if (this._resolved) { - runLater(function () { - wrappedResolvedCallback.apply(_this, _this._result); - }); - } else if (this._rejected) { - runLater(function () { - wrappedRejectedCallback(_this._error); - }); - } else { - this._resolvedCallbacks.push(wrappedResolvedCallback); - this._rejectedCallbacks.push(wrappedRejectedCallback); - } - - return promise; - } - - /** - * Add handlers to be called when the promise - * is either resolved or rejected - * @method always - */ - - }, { - key: 'always', - value: function (callback) { - return this.then(callback, callback); - } - - /** - * Add handlers to be called when the Promise object is resolved - * @method done - */ - - }, { - key: 'done', - value: function (callback) { - return this.then(callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * Alias for catch(). - * @method fail - */ - - }, { - key: 'fail', - value: function (callback) { - return this.then(null, callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * @method catch - */ - - }, { - key: 'catch', - value: function (callback) { - return this.then(null, callback); - } - - /** - * Run the given callbacks after this promise is fulfilled. - * @method _thenRunCallbacks - * @param optionsOrCallback {} A Backbone-style options callback, or a - * callback function. If this is an options object and contains a "model" - * attributes, that will be passed to error callbacks as the first argument. - * @param model {} If truthy, this will be passed as the first result of - * error callbacks. This is for Backbone-compatability. - * @return {Parse.Promise} A promise that will be resolved after the - * callbacks are run, with the same result as this. - */ - - }, { - key: '_thenRunCallbacks', - value: function (optionsOrCallback, model) { - var options = {}; - if (typeof optionsOrCallback === 'function') { - options.success = function (result) { - optionsOrCallback(result, null); - }; - options.error = function (error) { - optionsOrCallback(null, error); - }; - } else if ((typeof optionsOrCallback === 'undefined' ? 'undefined' : (0, _typeof3.default)(optionsOrCallback)) === 'object') { - if (typeof optionsOrCallback.success === 'function') { - options.success = optionsOrCallback.success; - } - if (typeof optionsOrCallback.error === 'function') { - options.error = optionsOrCallback.error; - } - } - - return this.then(function () { - for (var _len3 = arguments.length, results = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - results[_key3] = arguments[_key3]; - } - - if (options.success) { - options.success.apply(this, results); - } - return ParsePromise.as.apply(ParsePromise, arguments); - }, function (error) { - if (options.error) { - if (typeof model !== 'undefined') { - options.error(model, error); - } else { - options.error(error); - } - } - // By explicitly returning a rejected Promise, this will work with - // either jQuery or Promises/A+ semantics. - return ParsePromise.error(error); - }); - } - - /** - * Adds a callback function that should be called regardless of whether - * this promise failed or succeeded. The callback will be given either the - * array of results for its first argument, or the error as its second, - * depending on whether this Promise was rejected or resolved. Returns a - * new Promise, like "then" would. - * @method _continueWith - * @param {Function} continuation the callback. - */ - - }, { - key: '_continueWith', - value: function (continuation) { - return this.then(function () { - for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; - } - - return continuation(args, null); - }, function (error) { - return continuation(null, error); - }); - } - - /** - * Returns true iff the given object fulfils the Promise interface. - * @method is - * @param {Object} promise The object to test - * @static - * @return {Boolean} - */ - - }], [{ - key: 'is', - value: function (promise) { - return promise != null && typeof promise.then === 'function'; - } - - /** - * Returns a new promise that is resolved with a given value. - * @method as - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'as', - value: function () { - var promise = new ParsePromise(); - - for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - values[_key5] = arguments[_key5]; - } - - promise.resolve.apply(promise, values); - return promise; - } - - /** - * Returns a new promise that is resolved with a given value. - * If that value is a thenable Promise (has a .then() prototype - * method), the new promise will be chained to the end of the - * value. - * @method resolve - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'resolve', - value: function (value) { - return new ParsePromise(function (resolve, reject) { - if (ParsePromise.is(value)) { - value.then(resolve, reject); - } else { - resolve(value); - } - }); - } - - /** - * Returns a new promise that is rejected with a given error. - * @method error - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'error', - value: function () { - var promise = new ParsePromise(); - - for (var _len6 = arguments.length, errors = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - errors[_key6] = arguments[_key6]; - } - - promise.reject.apply(promise, errors); - return promise; - } - - /** - * Returns a new promise that is rejected with a given error. - * This is an alias for Parse.Promise.error, for compliance with - * the ES6 implementation. - * @method reject - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'reject', - value: function () { - for (var _len7 = arguments.length, errors = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - errors[_key7] = arguments[_key7]; - } - - return ParsePromise.error.apply(null, errors); - } - - /** - * Returns a new promise that is fulfilled when all of the input promises - * are resolved. If any promise in the list fails, then the returned promise - * will be rejected with an array containing the error from each promise. - * If they all succeed, then the returned promise will succeed, with the - * results being the results of all the input - * promises. For example:
                  -     *   var p1 = Parse.Promise.as(1);
                  -     *   var p2 = Parse.Promise.as(2);
                  -     *   var p3 = Parse.Promise.as(3);
                  -     *
                  -     *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
                  -     *     console.log(r1);  // prints 1
                  -     *     console.log(r2);  // prints 2
                  -     *     console.log(r3);  // prints 3
                  -     *   });
                  - * - * The input promises can also be specified as an array:
                  -     *   var promises = [p1, p2, p3];
                  -     *   Parse.Promise.when(promises).then(function(results) {
                  -     *     console.log(results);  // prints [1,2,3]
                  -     *   });
                  -     * 
                  - * @method when - * @param {Array} promises a list of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'when', - value: function (promises) { - var objects; - var arrayArgument = Array.isArray(promises); - if (arrayArgument) { - objects = promises; - } else { - objects = arguments; - } - - var total = objects.length; - var hadError = false; - var results = []; - var returnValue = arrayArgument ? [results] : results; - var errors = []; - results.length = objects.length; - errors.length = objects.length; - - if (total === 0) { - return ParsePromise.as.apply(this, returnValue); - } - - var promise = new ParsePromise(); - - var resolveOne = function () { - total--; - if (total <= 0) { - if (hadError) { - promise.reject(errors); - } else { - promise.resolve.apply(promise, returnValue); - } - } - }; - - var chain = function (object, index) { - if (ParsePromise.is(object)) { - object.then(function (result) { - results[index] = result; - resolveOne(); - }, function (error) { - errors[index] = error; - hadError = true; - resolveOne(); - }); - } else { - results[i] = object; - resolveOne(); - } - }; - for (var i = 0; i < objects.length; i++) { - chain(objects[i], i); - } - - return promise; - } - - /** - * Returns a new promise that is fulfilled when all of the promises in the - * iterable argument are resolved. If any promise in the list fails, then - * the returned promise will be immediately rejected with the reason that - * single promise rejected. If they all succeed, then the returned promise - * will succeed, with the results being the results of all the input - * promises. If the iterable provided is empty, the returned promise will - * be immediately resolved. - * - * For example:
                  -     *   var p1 = Parse.Promise.as(1);
                  -     *   var p2 = Parse.Promise.as(2);
                  -     *   var p3 = Parse.Promise.as(3);
                  -     *
                  -     *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
                  -     *     console.log(r1);  // prints 1
                  -     *     console.log(r2);  // prints 2
                  -     *     console.log(r3);  // prints 3
                  -     *   });
                  - * - * @method all - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'all', - value: function (promises) { - var total = 0; - var objects = []; - - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = (0, _getIterator3.default)(promises), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var p = _step.value; - - objects[total++] = p; - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - if (total === 0) { - return ParsePromise.as([]); - } - - var hadError = false; - var promise = new ParsePromise(); - var resolved = 0; - var results = []; - objects.forEach(function (object, i) { - if (ParsePromise.is(object)) { - object.then(function (result) { - if (hadError) { - return false; - } - results[i] = result; - resolved++; - if (resolved >= total) { - promise.resolve(results); - } - }, function (error) { - // Reject immediately - promise.reject(error); - hadError = true; - }); - } else { - results[i] = object; - resolved++; - if (!hadError && resolved >= total) { - promise.resolve(results); - } - } - }); - - return promise; - } - - /** - * Returns a new promise that is immediately fulfilled when any of the - * promises in the iterable argument are resolved or rejected. If the - * first promise to complete is resolved, the returned promise will be - * resolved with the same value. Likewise, if the first promise to - * complete is rejected, the returned promise will be rejected with the - * same reason. - * - * @method race - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'race', - value: function (promises) { - var completed = false; - var promise = new ParsePromise(); - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = (0, _getIterator3.default)(promises), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var p = _step2.value; - - if (ParsePromise.is(p)) { - p.then(function (result) { - if (completed) { - return; - } - completed = true; - promise.resolve(result); - }, function (error) { - if (completed) { - return; - } - completed = true; - promise.reject(error); - }); - } else if (!completed) { - completed = true; - promise.resolve(p); - } - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - return promise; - } - - /** - * Runs the given asyncFunction repeatedly, as long as the predicate - * function returns a truthy value. Stops repeating if asyncFunction returns - * a rejected promise. - * @method _continueWhile - * @param {Function} predicate should return false when ready to stop. - * @param {Function} asyncFunction should return a Promise. - * @static - */ - - }, { - key: '_continueWhile', - value: function (predicate, asyncFunction) { - if (predicate()) { - return asyncFunction().then(function () { - return ParsePromise._continueWhile(predicate, asyncFunction); - }); - } - return ParsePromise.as(); - } - }, { - key: 'isPromisesAPlusCompliant', - value: function () { - return _isPromisesAPlusCompliant; - } - }, { - key: 'enableAPlusCompliant', - value: function () { - _isPromisesAPlusCompliant = true; - } - }, { - key: 'disableAPlusCompliant', - value: function () { - _isPromisesAPlusCompliant = false; - } - }]); - return ParsePromise; -}(); - -exports.default = ParsePromise; -}).call(this,_dereq_('_process')) -},{"_process":168,"babel-runtime/core-js/get-iterator":43,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],21:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _keys = _dereq_('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _encode = _dereq_('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Converts a string into a regex that matches it. - * Surrounding with \Q .. \E does this, we just need to escape any \E's in - * the text separately. - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function quote(s) { - return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; -} - -/** - * Handles pre-populating the result data of a query with select fields, - * making sure that the data object contains keys for all objects that have - * been requested with a select, so that our cached state updates correctly. - */ -function handleSelectResult(data, select) { - var serverDataMask = {}; - - select.forEach(function (field) { - var hasSubObjectSelect = field.indexOf(".") !== -1; - if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { - // this field was selected, but is missing from the retrieved data - data[field] = undefined; - } else if (hasSubObjectSelect) { - // this field references a sub-object, - // so we need to walk down the path components - var pathComponents = field.split("."); - var obj = data; - var serverMask = serverDataMask; - - pathComponents.forEach(function (component, index, arr) { - // add keys if the expected data is missing - if (!obj[component]) { - obj[component] = index == arr.length - 1 ? undefined : {}; - } - obj = obj[component]; - - //add this path component to the server mask so we can fill it in later if needed - if (index < arr.length - 1) { - if (!serverMask[component]) { - serverMask[component] = {}; - } - } - }); - } - }); - - if ((0, _keys2.default)(serverDataMask).length > 0) { - var copyMissingDataWithMask = function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { - //copy missing elements at this level - if (copyThisLevel) { - for (var key in src) { - if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { - dest[key] = src[key]; - } - } - } - for (var key in mask) { - //traverse into objects as needed - copyMissingDataWithMask(src[key], dest[key], mask[key], true); - } - }; - - // When selecting from sub-objects, we don't want to blow away the missing - // information that we may have retrieved before. We've already added any - // missing selected keys to sub-objects, but we still need to add in the - // data for any previously retrieved sub-objects that were not selected. - - var serverData = _CoreManager2.default.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); - - copyMissingDataWithMask(serverData, data, serverDataMask, false); - } -} - -/** - * Creates a new parse Parse.Query for the given Parse.Object subclass. - * @class Parse.Query - * @constructor - * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. - * - *

                  Parse.Query defines a query that is used to fetch Parse.Objects. The - * most common use case is finding all objects that match a query through the - * find method. For example, this sample code fetches all objects - * of class MyClass. It calls a different function depending on - * whether the fetch succeeded or not. - * - *

                  - * var query = new Parse.Query(MyClass);
                  - * query.find({
                  - *   success: function(results) {
                  - *     // results is an array of Parse.Object.
                  - *   },
                  - *
                  - *   error: function(error) {
                  - *     // error is an instance of Parse.Error.
                  - *   }
                  - * });

                  - * - *

                  A Parse.Query can also be used to retrieve a single object whose id is - * known, through the get method. For example, this sample code fetches an - * object of class MyClass and id myId. It calls a - * different function depending on whether the fetch succeeded or not. - * - *

                  - * var query = new Parse.Query(MyClass);
                  - * query.get(myId, {
                  - *   success: function(object) {
                  - *     // object is an instance of Parse.Object.
                  - *   },
                  - *
                  - *   error: function(object, error) {
                  - *     // error is an instance of Parse.Error.
                  - *   }
                  - * });

                  - * - *

                  A Parse.Query can also be used to count the number of objects that match - * the query without retrieving all of those objects. For example, this - * sample code counts the number of objects of the class MyClass - *

                  - * var query = new Parse.Query(MyClass);
                  - * query.count({
                  - *   success: function(number) {
                  - *     // There are number instances of MyClass.
                  - *   },
                  - *
                  - *   error: function(error) {
                  - *     // error is an instance of Parse.Error.
                  - *   }
                  - * });

                  - */ - -var ParseQuery = function () { - function ParseQuery(objectClass) { - (0, _classCallCheck3.default)(this, ParseQuery); - - if (typeof objectClass === 'string') { - if (objectClass === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { - this.className = '_User'; - } else { - this.className = objectClass; - } - } else if (objectClass instanceof _ParseObject2.default) { - this.className = objectClass.className; - } else if (typeof objectClass === 'function') { - if (typeof objectClass.className === 'string') { - this.className = objectClass.className; - } else { - var obj = new objectClass(); - this.className = obj.className; - } - } else { - throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); - } - - this._where = {}; - this._include = []; - this._limit = -1; // negative limit is not sent in the server request - this._skip = 0; - this._extraOptions = {}; - } - - /** - * Adds constraint that at least one of the passed in queries matches. - * @method _orQuery - * @param {Array} queries - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - (0, _createClass3.default)(ParseQuery, [{ - key: '_orQuery', - value: function (queries) { - var queryJSON = queries.map(function (q) { - return q.toJSON().where; - }); - - this._where.$or = queryJSON; - return this; - } - - /** - * Helper for condition queries - */ - - }, { - key: '_addCondition', - value: function (key, condition, value) { - if (!this._where[key] || typeof this._where[key] === 'string') { - this._where[key] = {}; - } - this._where[key][condition] = (0, _encode2.default)(value, false, true); - return this; - } - - /** - * Converts string for regular expression at the beginning - */ - - }, { - key: '_regexStartWith', - value: function (string) { - return '^' + quote(string); - } - - /** - * Returns a JSON representation of this query. - * @method toJSON - * @return {Object} The JSON representation of the query. - */ - - }, { - key: 'toJSON', - value: function () { - var params = { - where: this._where - }; - - if (this._include.length) { - params.include = this._include.join(','); - } - if (this._select) { - params.keys = this._select.join(','); - } - if (this._limit >= 0) { - params.limit = this._limit; - } - if (this._skip > 0) { - params.skip = this._skip; - } - if (this._order) { - params.order = this._order.join(','); - } - for (var key in this._extraOptions) { - params[key] = this._extraOptions[key]; - } - - return params; - } - - /** - * Constructs a Parse.Object whose id is already known by fetching data from - * the server. Either options.success or options.error is called when the - * find completes. - * - * @method get - * @param {String} objectId The id of the object to be fetched. - * @param {Object} options A Backbone-style options object. - * Valid options are:
                    - *
                  • success: A Backbone-style success callback - *
                  • error: An Backbone-style error callback. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * - * @return {Parse.Promise} A promise that is resolved with the result when - * the query completes. - */ - - }, { - key: 'get', - value: function (objectId, options) { - this.equalTo('objectId', objectId); - - var firstOptions = {}; - if (options && options.hasOwnProperty('useMasterKey')) { - firstOptions.useMasterKey = options.useMasterKey; - } - if (options && options.hasOwnProperty('sessionToken')) { - firstOptions.sessionToken = options.sessionToken; - } - - return this.first(firstOptions).then(function (response) { - if (response) { - return response; - } - - var errorObject = new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'Object not found.'); - return _ParsePromise2.default.error(errorObject); - })._thenRunCallbacks(options, null); - } - - /** - * Retrieves a list of ParseObjects that satisfy this query. - * Either options.success or options.error is called when the find - * completes. - * - * @method find - * @param {Object} options A Backbone-style options object. Valid options - * are:
                    - *
                  • success: Function to call when the find completes successfully. - *
                  • error: Function to call when the find fails. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * - * @return {Parse.Promise} A promise that is resolved with the results when - * the query completes. - */ - - }, { - key: 'find', - value: function (options) { - var _this2 = this; - - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var select = this._select; - - return controller.find(this.className, this.toJSON(), findOptions).then(function (response) { - return response.results.map(function (data) { - // In cases of relations, the server may send back a className - // on the top level of the payload - var override = response.className || _this2.className; - if (!data.className) { - data.className = override; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(data, select); - } - - return _ParseObject2.default.fromJSON(data, !select); - }); - })._thenRunCallbacks(options); - } - - /** - * Counts the number of objects that match this query. - * Either options.success or options.error is called when the count - * completes. - * - * @method count - * @param {Object} options A Backbone-style options object. Valid options - * are:
                    - *
                  • success: Function to call when the count completes successfully. - *
                  • error: Function to call when the find fails. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * - * @return {Parse.Promise} A promise that is resolved with the count when - * the query completes. - */ - - }, { - key: 'count', - value: function (options) { - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var params = this.toJSON(); - params.limit = 0; - params.count = 1; - - return controller.find(this.className, params, findOptions).then(function (result) { - return result.count; - })._thenRunCallbacks(options); - } - - /** - * Retrieves at most one Parse.Object that satisfies this query. - * - * Either options.success or options.error is called when it completes. - * success is passed the object if there is one. otherwise, undefined. - * - * @method first - * @param {Object} options A Backbone-style options object. Valid options - * are:
                    - *
                  • success: Function to call when the find completes successfully. - *
                  • error: Function to call when the find fails. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * - * @return {Parse.Promise} A promise that is resolved with the object when - * the query completes. - */ - - }, { - key: 'first', - value: function (options) { - var _this3 = this; - - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var params = this.toJSON(); - params.limit = 1; - - var select = this._select; - - return controller.find(this.className, params, findOptions).then(function (response) { - var objects = response.results; - if (!objects[0]) { - return undefined; - } - if (!objects[0].className) { - objects[0].className = _this3.className; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(objects[0], select); - } - - return _ParseObject2.default.fromJSON(objects[0], !select); - })._thenRunCallbacks(options); - } - - /** - * Iterates over each result of a query, calling a callback for each one. If - * the callback returns a promise, the iteration will not continue until - * that promise has been fulfilled. If the callback returns a rejected - * promise, then iteration will stop with that error. The items are - * processed in an unspecified order. The query may not have any sort order, - * and may not use limit or skip. - * @method each - * @param {Function} callback Callback that will be called with each result - * of the query. - * @param {Object} options A Backbone-style options object. Valid options - * are:
                    - *
                  • success: Function to call when the iteration completes successfully. - *
                  • error: Function to call when the iteration fails. - *
                  • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                  • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                  - * @return {Parse.Promise} A promise that will be fulfilled once the - * iteration has completed. - */ - - }, { - key: 'each', - value: function (callback, options) { - options = options || {}; - - if (this._order || this._skip || this._limit >= 0) { - return _ParsePromise2.default.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); - } - - new _ParsePromise2.default(); - - - var query = new ParseQuery(this.className); - // We can override the batch size from the options. - // This is undocumented, but useful for testing. - query._limit = options.batchSize || 100; - query._include = this._include.map(function (i) { - return i; - }); - if (this._select) { - query._select = this._select.map(function (s) { - return s; - }); - } - - query._where = {}; - for (var attr in this._where) { - var val = this._where[attr]; - if (Array.isArray(val)) { - query._where[attr] = val.map(function (v) { - return v; - }); - } else if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object') { - var conditionMap = {}; - query._where[attr] = conditionMap; - for (var cond in val) { - conditionMap[cond] = val[cond]; - } - } else { - query._where[attr] = val; - } - } - - query.ascending('objectId'); - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var finished = false; - return _ParsePromise2.default._continueWhile(function () { - return !finished; - }, function () { - return query.find(findOptions).then(function (results) { - var callbacksDone = _ParsePromise2.default.as(); - results.forEach(function (result) { - callbacksDone = callbacksDone.then(function () { - return callback(result); - }); - }); - - return callbacksDone.then(function () { - if (results.length >= query._limit) { - query.greaterThan('objectId', results[results.length - 1].id); - } else { - finished = true; - } - }); - }); - })._thenRunCallbacks(options); - } - - /** Query Conditions **/ - - /** - * Adds a constraint to the query that requires a particular key's value to - * be equal to the provided value. - * @method equalTo - * @param {String} key The key to check. - * @param value The value that the Parse.Object must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'equalTo', - value: function (key, value) { - if (typeof value === 'undefined') { - return this.doesNotExist(key); - } - - this._where[key] = (0, _encode2.default)(value, false, true); - return this; - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be not equal to the provided value. - * @method notEqualTo - * @param {String} key The key to check. - * @param value The value that must not be equalled. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'notEqualTo', - value: function (key, value) { - return this._addCondition(key, '$ne', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than the provided value. - * @method lessThan - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'lessThan', - value: function (key, value) { - return this._addCondition(key, '$lt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than the provided value. - * @method greaterThan - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'greaterThan', - value: function (key, value) { - return this._addCondition(key, '$gt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than or equal to the provided value. - * @method lessThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'lessThanOrEqualTo', - value: function (key, value) { - return this._addCondition(key, '$lte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than or equal to the provided value. - * @method greaterThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'greaterThanOrEqualTo', - value: function (key, value) { - return this._addCondition(key, '$gte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be contained in the provided list of values. - * @method containedIn - * @param {String} key The key to check. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containedIn', - value: function (key, value) { - return this._addCondition(key, '$in', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * not be contained in the provided list of values. - * @method notContainedIn - * @param {String} key The key to check. - * @param {Array} values The values that will not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'notContainedIn', - value: function (key, value) { - return this._addCondition(key, '$nin', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values. - * @method containsAll - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containsAll', - value: function (key, values) { - return this._addCondition(key, '$all', values); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values starting with given strings. - * @method containsAllStartingWith - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The string values that will match as starting string. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containsAllStartingWith', - value: function (key, values) { - var _this = this; - if (!Array.isArray(values)) { - values = [values]; - } - - values = values.map(function (value) { - return { "$regex": _this._regexStartWith(value) }; - }); - - return this.containsAll(key, values); - } - - /** - * Adds a constraint for finding objects that contain the given key. - * @method exists - * @param {String} key The key that should exist. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'exists', - value: function (key) { - return this._addCondition(key, '$exists', true); - } - - /** - * Adds a constraint for finding objects that do not contain a given key. - * @method doesNotExist - * @param {String} key The key that should not exist - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotExist', - value: function (key) { - return this._addCondition(key, '$exists', false); - } - - /** - * Adds a regular expression constraint for finding string values that match - * the provided regular expression. - * This may be slow for large datasets. - * @method matches - * @param {String} key The key that the string to match is stored in. - * @param {RegExp} regex The regular expression pattern to match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matches', - value: function (key, regex, modifiers) { - this._addCondition(key, '$regex', regex); - if (!modifiers) { - modifiers = ''; - } - if (regex.ignoreCase) { - modifiers += 'i'; - } - if (regex.multiline) { - modifiers += 'm'; - } - if (modifiers.length) { - this._addCondition(key, '$options', modifiers); - } - return this; - } - - /** - * Adds a constraint that requires that a key's value matches a Parse.Query - * constraint. - * @method matchesQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matchesQuery', - value: function (key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$inQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value not matches a - * Parse.Query constraint. - * @method doesNotMatchQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotMatchQuery', - value: function (key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$notInQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value matches a value in - * an object returned by a different Parse.Query. - * @method matchesKeyInQuery - * @param {String} key The key that contains the value that is being - * matched. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matchesKeyInQuery', - value: function (key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$select', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint that requires that a key's value not match a value in - * an object returned by a different Parse.Query. - * @method doesNotMatchKeyInQuery - * @param {String} key The key that contains the value that is being - * excluded. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotMatchKeyInQuery', - value: function (key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$dontSelect', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint for finding string values that contain a provided - * string. This may be slow for large datasets. - * @method contains - * @param {String} key The key that the string to match is stored in. - * @param {String} substring The substring that the value must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'contains', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value)); - } - - /** - * Adds a constraint for finding string values that start with a provided - * string. This query will use the backend index, so it will be fast even - * for large datasets. - * @method startsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} prefix The substring that the value must start with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'startsWith', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', this._regexStartWith(value)); - } - - /** - * Adds a constraint for finding string values that end with a provided - * string. This will be slow for large datasets. - * @method endsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} suffix The substring that the value must end with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'endsWith', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value) + '$'); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given. - * @method near - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'near', - value: function (key, point) { - if (!(point instanceof _ParseGeoPoint2.default)) { - // Try to cast it as a GeoPoint - point = new _ParseGeoPoint2.default(point); - } - return this._addCondition(key, '$nearSphere', point); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * @method withinRadians - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in radians) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinRadians', - value: function (key, point, distance) { - this.near(key, point); - return this._addCondition(key, '$maxDistance', distance); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 3958.8 miles. - * @method withinMiles - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in miles) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinMiles', - value: function (key, point, distance) { - return this.withinRadians(key, point, distance / 3958.8); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 6371.0 kilometers. - * @method withinKilometers - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in kilometers) of results - * to return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinKilometers', - value: function (key, point, distance) { - return this.withinRadians(key, point, distance / 6371.0); - } - - /** - * Adds a constraint to the query that requires a particular key's - * coordinates be contained within a given rectangular geographic bounding - * box. - * @method withinGeoBox - * @param {String} key The key to be constrained. - * @param {Parse.GeoPoint} southwest - * The lower-left inclusive corner of the box. - * @param {Parse.GeoPoint} northeast - * The upper-right inclusive corner of the box. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinGeoBox', - value: function (key, southwest, northeast) { - if (!(southwest instanceof _ParseGeoPoint2.default)) { - southwest = new _ParseGeoPoint2.default(southwest); - } - if (!(northeast instanceof _ParseGeoPoint2.default)) { - northeast = new _ParseGeoPoint2.default(northeast); - } - this._addCondition(key, '$within', { '$box': [southwest, northeast] }); - return this; - } - - /** Query Orderings **/ - - /** - * Sorts the results in ascending order by the given key. - * - * @method ascending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'ascending', - value: function () { - this._order = []; - - for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) { - keys[_key] = arguments[_key]; - } - - return this.addAscending.apply(this, keys); - } - - /** - * Sorts the results in ascending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addAscending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'addAscending', - value: function () { - var _this4 = this; - - if (!this._order) { - this._order = []; - } - - for (var _len2 = arguments.length, keys = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - keys[_key2] = arguments[_key2]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - key = key.join(); - } - _this4._order = _this4._order.concat(key.replace(/\s/g, '').split(',')); - }); - - return this; - } - - /** - * Sorts the results in descending order by the given key. - * - * @method descending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'descending', - value: function () { - this._order = []; - - for (var _len3 = arguments.length, keys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - keys[_key3] = arguments[_key3]; - } - - return this.addDescending.apply(this, keys); - } - - /** - * Sorts the results in descending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addDescending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'addDescending', - value: function () { - var _this5 = this; - - if (!this._order) { - this._order = []; - } - - for (var _len4 = arguments.length, keys = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - keys[_key4] = arguments[_key4]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - key = key.join(); - } - _this5._order = _this5._order.concat(key.replace(/\s/g, '').split(',').map(function (k) { - return '-' + k; - })); - }); - - return this; - } - - /** Query Options **/ - - /** - * Sets the number of results to skip before returning any results. - * This is useful for pagination. - * Default is to skip zero results. - * @method skip - * @param {Number} n the number of results to skip. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'skip', - value: function (n) { - if (typeof n !== 'number' || n < 0) { - throw new Error('You can only skip by a positive number'); - } - this._skip = n; - return this; - } - - /** - * Sets the limit of the number of results to return. The default limit is - * 100, with a maximum of 1000 results being returned at a time. - * @method limit - * @param {Number} n the number of results to limit to. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'limit', - value: function (n) { - if (typeof n !== 'number') { - throw new Error('You can only set the limit to a numeric value'); - } - this._limit = n; - return this; - } - - /** - * Includes nested Parse.Objects for the provided key. You can use dot - * notation to specify which fields in the included object are also fetched. - * @method include - * @param {String} key The name of the key to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'include', - value: function () { - var _this6 = this; - - for (var _len5 = arguments.length, keys = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - keys[_key5] = arguments[_key5]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - _this6._include = _this6._include.concat(key); - } else { - _this6._include.push(key); - } - }); - return this; - } - - /** - * Restricts the fields of the returned Parse.Objects to include only the - * provided keys. If this is called multiple times, then all of the keys - * specified in each of the calls will be included. - * @method select - * @param {Array} keys The names of the keys to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'select', - value: function () { - var _this7 = this; - - if (!this._select) { - this._select = []; - } - - for (var _len6 = arguments.length, keys = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - keys[_key6] = arguments[_key6]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - _this7._select = _this7._select.concat(key); - } else { - _this7._select.push(key); - } - }); - return this; - } - - /** - * Subscribe this query to get liveQuery updates - * @method subscribe - * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter - * which can be used to get liveQuery updates. - */ - - }, { - key: 'subscribe', - value: function () { - var controller = _CoreManager2.default.getLiveQueryController(); - return controller.subscribe(this); - } - - /** - * Constructs a Parse.Query that is the OR of the passed in queries. For - * example: - *
                  var compoundQuery = Parse.Query.or(query1, query2, query3);
                  - * - * will create a compoundQuery that is an or of the query1, query2, and - * query3. - * @method or - * @param {...Parse.Query} var_args The list of queries to OR. - * @static - * @return {Parse.Query} The query that is the OR of the passed in queries. - */ - - }], [{ - key: 'or', - value: function () { - var className = null; - - for (var _len7 = arguments.length, queries = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - queries[_key7] = arguments[_key7]; - } - - queries.forEach(function (q) { - if (!className) { - className = q.className; - } - - if (className !== q.className) { - throw new Error('All queries must be for the same class.'); - } - }); - - var query = new ParseQuery(className); - query._orQuery(queries); - return query; - } - }]); - return ParseQuery; -}(); - -exports.default = ParseQuery; - -var DefaultController = { - find: function (className, params, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - return RESTController.request('GET', 'classes/' + className, params, options); - } -}; - -_CoreManager2.default.setQueryController(DefaultController); -},{"./CoreManager":3,"./ParseError":13,"./ParseGeoPoint":15,"./ParseObject":18,"./ParsePromise":20,"./encode":36,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],22:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParseOp = _dereq_('./ParseOp'); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseQuery = _dereq_('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new Relation for the given parent object and key. This - * constructor should rarely be used directly, but rather created by - * Parse.Object.relation. - * @class Parse.Relation - * @constructor - * @param {Parse.Object} parent The parent of this relation. - * @param {String} key The key for this relation on the parent. - * - *

                  - * A class that is used to access all of the children of a many-to-many - * relationship. Each instance of Parse.Relation is associated with a - * particular parent object and key. - *

                  - */ -var ParseRelation = function () { - function ParseRelation(parent, key) { - (0, _classCallCheck3.default)(this, ParseRelation); - - this.parent = parent; - this.key = key; - this.targetClassName = null; - } - - /** - * Makes sure that this relation has the right parent and key. - */ - - (0, _createClass3.default)(ParseRelation, [{ - key: '_ensureParentAndKey', - value: function (parent, key) { - this.key = this.key || key; - if (this.key !== key) { - throw new Error('Internal Error. Relation retrieved from two different keys.'); - } - if (this.parent) { - if (this.parent.className !== parent.className) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - if (this.parent.id) { - if (this.parent.id !== parent.id) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - } else if (parent.id) { - this.parent = parent; - } - } else { - this.parent = parent; - } - } - - /** - * Adds a Parse.Object or an array of Parse.Objects to the relation. - * @method add - * @param {} objects The item or items to add. - */ - - }, { - key: 'add', - value: function (objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new _ParseOp.RelationOp(objects, []); - var parent = this.parent; - if (!parent) { - throw new Error('Cannot add to a Relation without a parent'); - } - parent.set(this.key, change); - this.targetClassName = change._targetClassName; - return parent; - } - - /** - * Removes a Parse.Object or an array of Parse.Objects from this relation. - * @method remove - * @param {} objects The item or items to remove. - */ - - }, { - key: 'remove', - value: function (objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new _ParseOp.RelationOp([], objects); - if (!this.parent) { - throw new Error('Cannot remove from a Relation without a parent'); - } - this.parent.set(this.key, change); - this.targetClassName = change._targetClassName; - } - - /** - * Returns a JSON version of the object suitable for saving to disk. - * @method toJSON - * @return {Object} - */ - - }, { - key: 'toJSON', - value: function () { - return { - __type: 'Relation', - className: this.targetClassName - }; - } - - /** - * Returns a Parse.Query that is limited to objects in this - * relation. - * @method query - * @return {Parse.Query} - */ - - }, { - key: 'query', - value: function () { - var query; - var parent = this.parent; - if (!parent) { - throw new Error('Cannot construct a query for a Relation without a parent'); - } - if (!this.targetClassName) { - query = new _ParseQuery2.default(parent.className); - query._extraOptions.redirectClassNameForKey = this.key; - } else { - query = new _ParseQuery2.default(this.targetClassName); - } - query._addCondition('$relatedTo', 'object', { - __type: 'Pointer', - className: parent.className, - objectId: parent.id - }); - query._addCondition('$relatedTo', 'key', this.key); - - return query; - } - }]); - return ParseRelation; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseRelation; -},{"./ParseObject":18,"./ParseOp":19,"./ParseQuery":21,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],23:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _get2 = _dereq_('babel-runtime/helpers/get'); - -var _get3 = _interopRequireDefault(_get2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _ParseACL = _dereq_('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseObject2 = _dereq_('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Represents a Role on the Parse server. Roles represent groupings of - * Users for the purposes of granting permissions (e.g. specifying an ACL - * for an Object). Roles are specified by their sets of child users and - * child roles, all of which are granted any permissions that the parent - * role has. - * - *

                  Roles must have a name (which cannot be changed after creation of the - * role), and must specify an ACL.

                  - * @class Parse.Role - * @constructor - * @param {String} name The name of the Role to create. - * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. - * A Parse.Role is a local representation of a role persisted to the Parse - * cloud. - */ -var ParseRole = function (_ParseObject) { - (0, _inherits3.default)(ParseRole, _ParseObject); - - function ParseRole(name, acl) { - (0, _classCallCheck3.default)(this, ParseRole); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseRole.__proto__ || (0, _getPrototypeOf2.default)(ParseRole)).call(this, '_Role')); - - if (typeof name === 'string' && acl instanceof _ParseACL2.default) { - _this.setName(name); - _this.setACL(acl); - } - return _this; - } - - /** - * Gets the name of the role. You can alternatively call role.get("name") - * - * @method getName - * @return {String} the name of the role. - */ - - (0, _createClass3.default)(ParseRole, [{ - key: 'getName', - value: function () { - var name = this.get('name'); - if (name == null || typeof name === 'string') { - return name; - } - return ''; - } - - /** - * Sets the name for a role. This value must be set before the role has - * been saved to the server, and cannot be set once the role has been - * saved. - * - *

                  - * A role's name can only contain alphanumeric characters, _, -, and - * spaces. - *

                  - * - *

                  This is equivalent to calling role.set("name", name)

                  - * - * @method setName - * @param {String} name The name of the role. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - - }, { - key: 'setName', - value: function (name, options) { - return this.set('name', name, options); - } - - /** - * Gets the Parse.Relation for the Parse.Users that are direct - * children of this role. These users are granted any privileges that this - * role has been granted (e.g. read or write access through ACLs). You can - * add or remove users from the role through this relation. - * - *

                  This is equivalent to calling role.relation("users")

                  - * - * @method getUsers - * @return {Parse.Relation} the relation for the users belonging to this - * role. - */ - - }, { - key: 'getUsers', - value: function () { - return this.relation('users'); - } - - /** - * Gets the Parse.Relation for the Parse.Roles that are direct - * children of this role. These roles' users are granted any privileges that - * this role has been granted (e.g. read or write access through ACLs). You - * can add or remove child roles from this role through this relation. - * - *

                  This is equivalent to calling role.relation("roles")

                  - * - * @method getRoles - * @return {Parse.Relation} the relation for the roles belonging to this - * role. - */ - - }, { - key: 'getRoles', - value: function () { - return this.relation('roles'); - } - }, { - key: 'validate', - value: function (attrs, options) { - var isInvalid = (0, _get3.default)(ParseRole.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseRole.prototype), 'validate', this).call(this, attrs, options); - if (isInvalid) { - return isInvalid; - } - - if ('name' in attrs && attrs.name !== this.getName()) { - var newName = attrs.name; - if (this.id && this.id !== attrs.objectId) { - // Check to see if the objectId being set matches this.id - // This happens during a fetch -- the id is set before calling fetch - // Let the name be set in this case - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); - } - if (typeof newName !== 'string') { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name must be a String.'); - } - if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); - } - } - return false; - } - }]); - return ParseRole; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseRole; - -_ParseObject3.default.registerSubclass('_Role', ParseRole); -},{"./ParseACL":11,"./ParseError":13,"./ParseObject":18,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/get":58,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],24:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _isRevocableSession = _dereq_('./isRevocableSession'); - -var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); - -var _ParseObject2 = _dereq_('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseUser = _dereq_('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * @class Parse.Session - * @constructor - * - *

                  A Parse.Session object is a local representation of a revocable session. - * This class is a subclass of a Parse.Object, and retains the same - * functionality of a Parse.Object.

                  - */ -var ParseSession = function (_ParseObject) { - (0, _inherits3.default)(ParseSession, _ParseObject); - - function ParseSession(attributes) { - (0, _classCallCheck3.default)(this, ParseSession); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseSession.__proto__ || (0, _getPrototypeOf2.default)(ParseSession)).call(this, '_Session')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - return _this; - } - - /** - * Returns the session token string. - * @method getSessionToken - * @return {String} - */ - - (0, _createClass3.default)(ParseSession, [{ - key: 'getSessionToken', - value: function () { - var token = this.get('sessionToken'); - if (typeof token === 'string') { - return token; - } - return ''; - } - }], [{ - key: 'readOnlyAttributes', - value: function () { - return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; - } - - /** - * Retrieves the Session object for the currently logged in session. - * @method current - * @static - * @return {Parse.Promise} A promise that is resolved with the Parse.Session - * object after it has been fetched. If there is no current user, the - * promise will be rejected. - */ - - }, { - key: 'current', - value: function (options) { - options = options || {}; - var controller = _CoreManager2.default.getSessionController(); - - var sessionOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - sessionOptions.useMasterKey = options.useMasterKey; - } - return _ParseUser2.default.currentAsync().then(function (user) { - if (!user) { - return _ParsePromise2.default.error('There is no current user.'); - } - user.getSessionToken(); - - sessionOptions.sessionToken = user.getSessionToken(); - return controller.getSession(sessionOptions); - }); - } - - /** - * Determines whether the current session token is revocable. - * This method is useful for migrating Express.js or Node.js web apps to - * use revocable sessions. If you are migrating an app that uses the Parse - * SDK in the browser only, please use Parse.User.enableRevocableSession() - * instead, so that sessions can be automatically upgraded. - * @method isCurrentSessionRevocable - * @static - * @return {Boolean} - */ - - }, { - key: 'isCurrentSessionRevocable', - value: function () { - var currentUser = _ParseUser2.default.current(); - if (currentUser) { - return (0, _isRevocableSession2.default)(currentUser.getSessionToken() || ''); - } - return false; - } - }]); - return ParseSession; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseSession; - -_ParseObject3.default.registerSubclass('_Session', ParseSession); - -var DefaultController = { - getSession: function (options) { - var RESTController = _CoreManager2.default.getRESTController(); - var session = new ParseSession(); - - return RESTController.request('GET', 'sessions/me', {}, options).then(function (sessionData) { - session._finishFetch(sessionData); - session._setExisted(true); - return session; - }); - } -}; - -_CoreManager2.default.setSessionController(DefaultController); -},{"./CoreManager":3,"./ParseObject":18,"./ParsePromise":20,"./ParseUser":25,"./isRevocableSession":39,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],25:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _defineProperty = _dereq_('babel-runtime/core-js/object/define-property'); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = _dereq_('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = _dereq_('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _get2 = _dereq_('babel-runtime/helpers/get'); - -var _get3 = _interopRequireDefault(_get2); - -var _inherits2 = _dereq_('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _isRevocableSession = _dereq_('./isRevocableSession'); - -var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseObject2 = _dereq_('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseSession = _dereq_('./ParseSession'); - -var _ParseSession2 = _interopRequireDefault(_ParseSession); - -var _Storage = _dereq_('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var CURRENT_USER_KEY = 'currentUser'; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var canUseCurrentUser = !_CoreManager2.default.get('IS_NODE'); -var currentUserCacheMatchesDisk = false; -var currentUserCache = null; - -var authProviders = {}; - -/** - * @class Parse.User - * @constructor - * - *

                  A Parse.User object is a local representation of a user persisted to the - * Parse cloud. This class is a subclass of a Parse.Object, and retains the - * same functionality of a Parse.Object, but also extends it with various - * user specific methods, like authentication, signing up, and validation of - * uniqueness.

                  - */ - -var ParseUser = function (_ParseObject) { - (0, _inherits3.default)(ParseUser, _ParseObject); - - function ParseUser(attributes) { - (0, _classCallCheck3.default)(this, ParseUser); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseUser.__proto__ || (0, _getPrototypeOf2.default)(ParseUser)).call(this, '_User')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Parse User'); - } - } - return _this; - } - - /** - * Request a revocable session token to replace the older style of token. - * @method _upgradeToRevocableSession - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is resolved when the replacement - * token has been fetched. - */ - - (0, _createClass3.default)(ParseUser, [{ - key: '_upgradeToRevocableSession', - value: function (options) { - options = options || {}; - - var upgradeOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - upgradeOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); - } - - /** - * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can - * call linkWith on the user (even if it doesn't exist yet on the server). - * @method _linkWith - */ - - }, { - key: '_linkWith', - value: function (provider, options) { - var _this2 = this; - - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[provider]; - } else { - authType = provider.getAuthType(); - } - if (options && options.hasOwnProperty('authData')) { - var authData = this.get('authData') || {}; - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - throw new Error('Invalid type: authData field should be an object'); - } - authData[authType] = options.authData; - - var controller = _CoreManager2.default.getUserController(); - return controller.linkWith(this, authData)._thenRunCallbacks(options, this); - } else { - var promise = new _ParsePromise2.default(); - provider.authenticate({ - success: function (provider, result) { - var opts = {}; - opts.authData = result; - if (options.success) { - opts.success = options.success; - } - if (options.error) { - opts.error = options.error; - } - _this2._linkWith(provider, opts).then(function () { - promise.resolve(_this2); - }, function (error) { - promise.reject(error); - }); - }, - error: function (provider, _error) { - if (typeof options.error === 'function') { - options.error(_this2, _error); - } - promise.reject(_error); - } - }); - return promise; - } - } - - /** - * Synchronizes auth data for a provider (e.g. puts the access token in the - * right place to be used by the Facebook SDK). - * @method _synchronizeAuthData - */ - - }, { - key: '_synchronizeAuthData', - value: function (provider) { - if (!this.isCurrent() || !provider) { - return; - } - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[authType]; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData'); - if (!provider || !authData || (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - var success = provider.restoreAuthentication(authData[authType]); - if (!success) { - this._unlinkFrom(provider); - } - } - - /** - * Synchronizes authData for all providers. - * @method _synchronizeAllAuthData - */ - - }, { - key: '_synchronizeAllAuthData', - value: function () { - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - this._synchronizeAuthData(key); - } - } - - /** - * Removes null values from authData (which exist temporarily for - * unlinking) - * @method _cleanupAuthData - */ - - }, { - key: '_cleanupAuthData', - value: function () { - if (!this.isCurrent()) { - return; - } - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - if (!authData[key]) { - delete authData[key]; - } - } - } - - /** - * Unlinks a user from a service. - * @method _unlinkFrom - */ - - }, { - key: '_unlinkFrom', - value: function (provider, options) { - var _this3 = this; - - if (typeof provider === 'string') { - provider = authProviders[provider]; - } else { - provider.getAuthType(); - } - return this._linkWith(provider, { authData: null }).then(function () { - _this3._synchronizeAuthData(provider); - return _ParsePromise2.default.as(_this3); - })._thenRunCallbacks(options); - } - - /** - * Checks whether a user is linked to a service. - * @method _isLinked - */ - - }, { - key: '_isLinked', - value: function (provider) { - var authType; - if (typeof provider === 'string') { - authType = provider; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData') || {}; - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return false; - } - return !!authData[authType]; - } - - /** - * Deauthenticates all providers. - * @method _logOutWithAll - */ - - }, { - key: '_logOutWithAll', - value: function () { - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - this._logOutWith(key); - } - } - - /** - * Deauthenticates a single provider (e.g. removing access tokens from the - * Facebook SDK). - * @method _logOutWith - */ - - }, { - key: '_logOutWith', - value: function (provider) { - if (!this.isCurrent()) { - return; - } - if (typeof provider === 'string') { - provider = authProviders[provider]; - } - if (provider && provider.deauthenticate) { - provider.deauthenticate(); - } - } - - /** - * Class instance method used to maintain specific keys when a fetch occurs. - * Used to ensure that the session token is not lost. - */ - - }, { - key: '_preserveFieldsOnFetch', - value: function () { - return { - sessionToken: this.get('sessionToken') - }; - } - - /** - * Returns true if current would return this user. - * @method isCurrent - * @return {Boolean} - */ - - }, { - key: 'isCurrent', - value: function () { - var current = ParseUser.current(); - return !!current && current.id === this.id; - } - - /** - * Returns get("username"). - * @method getUsername - * @return {String} - */ - - }, { - key: 'getUsername', - value: function () { - var username = this.get('username'); - if (username == null || typeof username === 'string') { - return username; - } - return ''; - } - - /** - * Calls set("username", username, options) and returns the result. - * @method setUsername - * @param {String} username - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setUsername', - value: function (username) { - // Strip anonymity, even we do not support anonymous user in js SDK, we may - // encounter anonymous user created by android/iOS in cloud code. - var authData = this.get('authData'); - if (authData && (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) === 'object' && authData.hasOwnProperty('anonymous')) { - // We need to set anonymous to null instead of deleting it in order to remove it from Parse. - authData.anonymous = null; - } - this.set('username', username); - } - - /** - * Calls set("password", password, options) and returns the result. - * @method setPassword - * @param {String} password - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setPassword', - value: function (password) { - this.set('password', password); - } - - /** - * Returns get("email"). - * @method getEmail - * @return {String} - */ - - }, { - key: 'getEmail', - value: function () { - var email = this.get('email'); - if (email == null || typeof email === 'string') { - return email; - } - return ''; - } - - /** - * Calls set("email", email, options) and returns the result. - * @method setEmail - * @param {String} email - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setEmail', - value: function (email) { - this.set('email', email); - } - - /** - * Returns the session token for this user, if the user has been logged in, - * or if it is the result of a query with the master key. Otherwise, returns - * undefined. - * @method getSessionToken - * @return {String} the session token, or undefined - */ - - }, { - key: 'getSessionToken', - value: function () { - var token = this.get('sessionToken'); - if (token == null || typeof token === 'string') { - return token; - } - return ''; - } - - /** - * Checks whether this user is the current user and has been authenticated. - * @method authenticated - * @return (Boolean) whether this user is the current user and is logged in. - */ - - }, { - key: 'authenticated', - value: function () { - var current = ParseUser.current(); - return !!this.get('sessionToken') && !!current && current.id === this.id; - } - - /** - * Signs up a new user. You should call this instead of save for - * new Parse.Users. This will create a new Parse.User on the server, and - * also persist the session on disk so that you can access the user using - * current. - * - *

                  A username and password must be set before calling signUp.

                  - * - *

                  Calls options.success or options.error on completion.

                  - * - * @method signUp - * @param {Object} attrs Extra fields to set on the new user, or null. - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled when the signup - * finishes. - */ - - }, { - key: 'signUp', - value: function (attrs, options) { - options = options || {}; - - var signupOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - signupOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - signupOptions.installationId = options.installationId; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); - } - - /** - * Logs in a Parse.User. On success, this saves the session to disk, - * so you can retrieve the currently logged in user using - * current. - * - *

                  A username and password must be set before calling logIn.

                  - * - *

                  Calls options.success or options.error on completion.

                  - * - * @method logIn - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login is complete. - */ - - }, { - key: 'logIn', - value: function (options) { - options = options || {}; - - var loginOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - loginOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - loginOptions.installationId = options.installationId; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); - } - - /** - * Wrap the default save behavior with functionality to save to local - * storage if this is current user. - */ - - }, { - key: 'save', - value: function () { - var _this4 = this; - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'save', this).apply(this, args).then(function () { - if (_this4.isCurrent()) { - return _CoreManager2.default.getUserController().updateUserOnDisk(_this4); - } - return _this4; - }); - } - - /** - * Wrap the default destroy behavior with functionality that logs out - * the current user when it is destroyed - */ - - }, { - key: 'destroy', - value: function () { - var _this5 = this; - - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'destroy', this).apply(this, args).then(function () { - if (_this5.isCurrent()) { - return _CoreManager2.default.getUserController().removeUserFromDisk(); - } - return _this5; - }); - } - - /** - * Wrap the default fetch behavior with functionality to save to local - * storage if this is current user. - */ - - }, { - key: 'fetch', - value: function () { - var _this6 = this; - - for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'fetch', this).apply(this, args).then(function () { - if (_this6.isCurrent()) { - return _CoreManager2.default.getUserController().updateUserOnDisk(_this6); - } - return _this6; - }); - } - }], [{ - key: 'readOnlyAttributes', - value: function () { - return ['sessionToken']; - } - - /** - * Adds functionality to the existing Parse.User class - * @method extend - * @param {Object} protoProps A set of properties to add to the prototype - * @param {Object} classProps A set of static properties to add to the class - * @static - * @return {Class} The newly extended Parse.User class - */ - - }, { - key: 'extend', - value: function (protoProps, classProps) { - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseUser.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseUser, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - return ParseUser; - } - - /** - * Retrieves the currently logged in ParseUser with a valid session, - * either from memory or localStorage, if necessary. - * @method current - * @static - * @return {Parse.Object} The currently logged in Parse.User. - */ - - }, { - key: 'current', - value: function () { - if (!canUseCurrentUser) { - return null; - } - var controller = _CoreManager2.default.getUserController(); - return controller.currentUser(); - } - - /** - * Retrieves the currently logged in ParseUser from asynchronous Storage. - * @method currentAsync - * @static - * @return {Parse.Promise} A Promise that is resolved with the currently - * logged in Parse User - */ - - }, { - key: 'currentAsync', - value: function () { - if (!canUseCurrentUser) { - return _ParsePromise2.default.as(null); - } - var controller = _CoreManager2.default.getUserController(); - return controller.currentUserAsync(); - } - - /** - * Signs up a new user with a username (or email) and password. - * This will create a new Parse.User on the server, and also persist the - * session in localStorage so that you can access the user using - * {@link #current}. - * - *

                  Calls options.success or options.error on completion.

                  - * - * @method signUp - * @param {String} username The username (or email) to sign up with. - * @param {String} password The password to sign up with. - * @param {Object} attrs Extra fields to set on the new user. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the signup completes. - */ - - }, { - key: 'signUp', - value: function (username, password, attrs, options) { - attrs = attrs || {}; - attrs.username = username; - attrs.password = password; - var user = new ParseUser(attrs); - return user.signUp({}, options); - } - - /** - * Logs in a user with a username (or email) and password. On success, this - * saves the session to disk, so you can retrieve the currently logged in - * user using current. - * - *

                  Calls options.success or options.error on completion.

                  - * - * @method logIn - * @param {String} username The username (or email) to log in with. - * @param {String} password The password to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - - }, { - key: 'logIn', - value: function (username, password, options) { - if (typeof username !== 'string') { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Username must be a string.')); - } else if (typeof password !== 'string') { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Password must be a string.')); - } - var user = new ParseUser(); - user._finishFetch({ username: username, password: password }); - return user.logIn(options); - } - - /** - * Logs in a user with a session token. On success, this saves the session - * to disk, so you can retrieve the currently logged in user using - * current. - * - *

                  Calls options.success or options.error on completion.

                  - * - * @method become - * @param {String} sessionToken The sessionToken to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - - }, { - key: 'become', - value: function (sessionToken, options) { - if (!canUseCurrentUser) { - throw new Error('It is not memory-safe to become a user in a server environment'); - } - options = options || {}; - - var becomeOptions = { - sessionToken: sessionToken - }; - if (options.hasOwnProperty('useMasterKey')) { - becomeOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.become(becomeOptions)._thenRunCallbacks(options); - } - }, { - key: 'logInWith', - value: function (provider, options) { - return ParseUser._logInWith(provider, options); - } - - /** - * Logs out the currently logged in user session. This will remove the - * session from disk, log out of linked services, and future calls to - * current will return null. - * @method logOut - * @static - * @return {Parse.Promise} A promise that is resolved when the session is - * destroyed on the server. - */ - - }, { - key: 'logOut', - value: function () { - if (!canUseCurrentUser) { - throw new Error('There is no current user user on a node.js server environment.'); - } - - var controller = _CoreManager2.default.getUserController(); - return controller.logOut(); - } - - /** - * Requests a password reset email to be sent to the specified email address - * associated with the user account. This email allows the user to securely - * reset their password on the Parse site. - * - *

                  Calls options.success or options.error on completion.

                  - * - * @method requestPasswordReset - * @param {String} email The email address associated with the user that - * forgot their password. - * @param {Object} options A Backbone-style options object. - * @static - */ - - }, { - key: 'requestPasswordReset', - value: function (email, options) { - options = options || {}; - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); - } - - /** - * Allow someone to define a custom User class without className - * being rewritten to _User. The default behavior is to rewrite - * User to _User for legacy reasons. This allows developers to - * override that behavior. - * - * @method allowCustomUserClass - * @param {Boolean} isAllowed Whether or not to allow custom User class - * @static - */ - - }, { - key: 'allowCustomUserClass', - value: function (isAllowed) { - _CoreManager2.default.set('PERFORM_USER_REWRITE', !isAllowed); - } - - /** - * Allows a legacy application to start using revocable sessions. If the - * current session token is not revocable, a request will be made for a new, - * revocable session. - * It is not necessary to call this method from cloud code unless you are - * handling user signup or login from the server side. In a cloud code call, - * this function will not attempt to upgrade the current token. - * @method enableRevocableSession - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is resolved when the process has - * completed. If a replacement session token is requested, the promise - * will be resolved after a new token has been fetched. - */ - - }, { - key: 'enableRevocableSession', - value: function (options) { - options = options || {}; - _CoreManager2.default.set('FORCE_REVOCABLE_SESSION', true); - if (canUseCurrentUser) { - var current = ParseUser.current(); - if (current) { - return current._upgradeToRevocableSession(options); - } - } - return _ParsePromise2.default.as()._thenRunCallbacks(options); - } - - /** - * Enables the use of become or the current user in a server - * environment. These features are disabled by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method enableUnsafeCurrentUser - * @static - */ - - }, { - key: 'enableUnsafeCurrentUser', - value: function () { - canUseCurrentUser = true; - } - - /** - * Disables the use of become or the current user in any environment. - * These features are disabled on servers by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method disableUnsafeCurrentUser - * @static - */ - - }, { - key: 'disableUnsafeCurrentUser', - value: function () { - canUseCurrentUser = false; - } - }, { - key: '_registerAuthenticationProvider', - value: function (provider) { - authProviders[provider.getAuthType()] = provider; - // Synchronize the current user with the auth provider. - ParseUser.currentAsync().then(function (current) { - if (current) { - current._synchronizeAuthData(provider.getAuthType()); - } - }); - } - }, { - key: '_logInWith', - value: function (provider, options) { - var user = new ParseUser(); - return user._linkWith(provider, options); - } - }, { - key: '_clearCache', - value: function () { - currentUserCache = null; - currentUserCacheMatchesDisk = false; - } - }, { - key: '_setCurrentUserCache', - value: function (user) { - currentUserCache = user; - } - }]); - return ParseUser; -}(_ParseObject3.default); - -exports.default = ParseUser; - -_ParseObject3.default.registerSubclass('_User', ParseUser); - -var DefaultController = { - updateUserOnDisk: function (user) { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var json = user.toJSON(); - json.className = '_User'; - return _Storage2.default.setItemAsync(path, (0, _stringify2.default)(json)).then(function () { - return user; - }); - }, - removeUserFromDisk: function () { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - currentUserCacheMatchesDisk = true; - currentUserCache = null; - return _Storage2.default.removeItemAsync(path); - }, - setCurrentUser: function (user) { - currentUserCache = user; - user._cleanupAuthData(); - user._synchronizeAllAuthData(); - return DefaultController.updateUserOnDisk(user); - }, - currentUser: function () { - if (currentUserCache) { - return currentUserCache; - } - if (currentUserCacheMatchesDisk) { - return null; - } - if (_Storage2.default.async()) { - throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); - } - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var userData = _Storage2.default.getItem(path); - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return null; - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = _ParseObject3.default.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return current; - }, - currentUserAsync: function () { - if (currentUserCache) { - return _ParsePromise2.default.as(currentUserCache); - } - if (currentUserCacheMatchesDisk) { - return _ParsePromise2.default.as(null); - } - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - return _Storage2.default.getItemAsync(path).then(function (userData) { - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return _ParsePromise2.default.as(null); - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = _ParseObject3.default.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return _ParsePromise2.default.as(current); - }); - }, - signUp: function (user, attrs, options) { - var username = attrs && attrs.username || user.get('username'); - var password = attrs && attrs.password || user.get('password'); - - if (!username || !username.length) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); - } - if (!password || !password.length) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); - } - - return user.save(attrs, options).then(function () { - // Clear the password field - user._finishFetch({ password: undefined }); - - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - }, - logIn: function (user, options) { - var RESTController = _CoreManager2.default.getRESTController(); - var stateController = _CoreManager2.default.getObjectStateController(); - var auth = { - username: user.get('username'), - password: user.get('password') - }; - return RESTController.request('GET', 'login', auth, options).then(function (response, status) { - user._migrateId(response.objectId); - user._setExisted(true); - stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); - stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); - response.password = undefined; - user._finishFetch(response); - if (!canUseCurrentUser) { - // We can't set the current user, so just return the one we logged in - return _ParsePromise2.default.as(user); - } - return DefaultController.setCurrentUser(user); - }); - }, - become: function (options) { - var user = new ParseUser(); - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('GET', 'users/me', {}, options).then(function (response, status) { - user._finishFetch(response); - user._setExisted(true); - return DefaultController.setCurrentUser(user); - }); - }, - logOut: function () { - return DefaultController.currentUserAsync().then(function (currentUser) { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var promise = _Storage2.default.removeItemAsync(path); - var RESTController = _CoreManager2.default.getRESTController(); - if (currentUser !== null) { - var currentSession = currentUser.getSessionToken(); - if (currentSession && (0, _isRevocableSession2.default)(currentSession)) { - promise = promise.then(function () { - return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); - }); - } - currentUser._logOutWithAll(); - currentUser._finishFetch({ sessionToken: undefined }); - } - currentUserCacheMatchesDisk = true; - currentUserCache = null; - - return promise; - }); - }, - requestPasswordReset: function (email, options) { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); - }, - upgradeToRevocableSession: function (user, options) { - var token = user.getSessionToken(); - if (!token) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.SESSION_MISSING, 'Cannot upgrade a user with no session token')); - } - - options.sessionToken = token; - - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(function (result) { - var session = new _ParseSession2.default(); - session._finishFetch(result); - user._finishFetch({ sessionToken: session.getSessionToken() }); - if (user.isCurrent()) { - return DefaultController.setCurrentUser(user); - } - return _ParsePromise2.default.as(user); - }); - }, - linkWith: function (user, authData) { - return user.save({ authData: authData }).then(function () { - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - } -}; - -_CoreManager2.default.setUserController(DefaultController); -},{"./CoreManager":3,"./ParseError":13,"./ParseObject":18,"./ParsePromise":20,"./ParseSession":24,"./Storage":29,"./isRevocableSession":39,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/object/define-property":47,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/get":58,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],26:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.send = send; - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParseQuery = _dereq_('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains functions to deal with Push in Parse. - * @class Parse.Push - * @static - */ - -/** - * Sends a push notification. - * @method send - * @param {Object} data - The data of the push notification. Valid fields - * are: - *
                    - *
                  1. channels - An Array of channels to push to.
                  2. - *
                  3. push_time - A Date object for when to send the push.
                  4. - *
                  5. expiration_time - A Date object for when to expire - * the push.
                  6. - *
                  7. expiration_interval - The seconds from now to expire the push.
                  8. - *
                  9. where - A Parse.Query over Parse.Installation that is used to match - * a set of installations to push to.
                  10. - *
                  11. data - The data to send as part of the push
                  12. - *
                      - * @param {Object} options An object that has an optional success function, - * that takes no arguments and will be called on a successful push, and - * an error function that takes a Parse.Error and will be called if the push - * failed. - * @return {Parse.Promise} A promise that is fulfilled when the push request - * completes. - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function send(data, options) { - options = options || {}; - - if (data.where && data.where instanceof _ParseQuery2.default) { - data.where = data.where.toJSON().where; - } - - if (data.push_time && (0, _typeof3.default)(data.push_time) === 'object') { - data.push_time = data.push_time.toJSON(); - } - - if (data.expiration_time && (0, _typeof3.default)(data.expiration_time) === 'object') { - data.expiration_time = data.expiration_time.toJSON(); - } - - if (data.expiration_time && data.expiration_interval) { - throw new Error('expiration_time and expiration_interval cannot both be set.'); - } - - return _CoreManager2.default.getPushController().send(data, { - useMasterKey: options.useMasterKey - })._thenRunCallbacks(options); -} - -var DefaultController = { - send: function (data, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); - - return request._thenRunCallbacks(options); - } -}; - -_CoreManager2.default.setPushController(DefaultController); -},{"./CoreManager":3,"./ParseQuery":21,"babel-runtime/helpers/typeof":61}],27:[function(_dereq_,module,exports){ -(function (process){ -'use strict'; - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _stringify = _dereq_('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParseError = _dereq_('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = _dereq_('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var XHR = null; -if (typeof XMLHttpRequest !== 'undefined') { - XHR = XMLHttpRequest; -} - - -var useXDomainRequest = false; -if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { - useXDomainRequest = true; -} - -function ajaxIE9(method, url, data) { - var promise = new _ParsePromise2.default(); - var xdr = new XDomainRequest(); - xdr.onload = function () { - var response; - try { - response = JSON.parse(xdr.responseText); - } catch (e) { - promise.reject(e); - } - if (response) { - promise.resolve(response); - } - }; - xdr.onerror = xdr.ontimeout = function () { - // Let's fake a real error message. - var fakeResponse = { - responseText: (0, _stringify2.default)({ - code: _ParseError2.default.X_DOMAIN_REQUEST, - error: 'IE\'s XDomainRequest does not supply error info.' - }) - }; - promise.reject(fakeResponse); - }; - xdr.onprogress = function () {}; - xdr.open(method, url); - xdr.send(data); - return promise; -} - -var RESTController = { - ajax: function (method, url, data, headers) { - if (useXDomainRequest) { - return ajaxIE9(method, url, data, headers); - } - - var promise = new _ParsePromise2.default(); - var attempts = 0; - - (function dispatch() { - if (XHR == null) { - throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); - } - var handled = false; - var xhr = new XHR(); - - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4 || handled) { - return; - } - handled = true; - - if (xhr.status >= 200 && xhr.status < 300) { - var response; - try { - response = JSON.parse(xhr.responseText); - } catch (e) { - promise.reject(e.toString()); - } - if (response) { - promise.resolve(response, xhr.status, xhr); - } - } else if (xhr.status >= 500 || xhr.status === 0) { - // retry on 5XX or node-xmlhttprequest error - if (++attempts < _CoreManager2.default.get('REQUEST_ATTEMPT_LIMIT')) { - // Exponentially-growing random delay - var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); - setTimeout(dispatch, delay); - } else if (xhr.status === 0) { - promise.reject('Unable to connect to the Parse API'); - } else { - // After the retry limit is reached, fail - promise.reject(xhr); - } - } else { - promise.reject(xhr); - } - }; - - headers = headers || {}; - if (typeof headers['Content-Type'] !== 'string') { - headers['Content-Type'] = 'text/plain'; // Avoid pre-flight - } - if (_CoreManager2.default.get('IS_NODE')) { - headers['User-Agent'] = 'Parse/' + _CoreManager2.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; - } - - xhr.open(method, url, true); - for (var h in headers) { - xhr.setRequestHeader(h, headers[h]); - } - xhr.send(data); - })(); - - return promise; - }, - request: function (method, path, data, options) { - options = options || {}; - var url = _CoreManager2.default.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += path; - - var payload = {}; - if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') { - for (var k in data) { - payload[k] = data[k]; - } - } - - if (method !== 'POST') { - payload._method = method; - method = 'POST'; - } - - payload._ApplicationId = _CoreManager2.default.get('APPLICATION_ID'); - var jsKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); - if (jsKey) { - payload._JavaScriptKey = jsKey; - } - payload._ClientVersion = _CoreManager2.default.get('VERSION'); - - var useMasterKey = options.useMasterKey; - if (typeof useMasterKey === 'undefined') { - useMasterKey = _CoreManager2.default.get('USE_MASTER_KEY'); - } - if (useMasterKey) { - if (_CoreManager2.default.get('MASTER_KEY')) { - delete payload._JavaScriptKey; - payload._MasterKey = _CoreManager2.default.get('MASTER_KEY'); - } else { - throw new Error('Cannot use the Master Key, it has not been provided.'); - } - } - - if (_CoreManager2.default.get('FORCE_REVOCABLE_SESSION')) { - payload._RevocableSession = '1'; - } - - var installationId = options.installationId; - var installationIdPromise; - if (installationId && typeof installationId === 'string') { - installationIdPromise = _ParsePromise2.default.as(installationId); - } else { - var installationController = _CoreManager2.default.getInstallationController(); - installationIdPromise = installationController.currentInstallationId(); - } - - return installationIdPromise.then(function (iid) { - payload._InstallationId = iid; - var userController = _CoreManager2.default.getUserController(); - if (options && typeof options.sessionToken === 'string') { - return _ParsePromise2.default.as(options.sessionToken); - } else if (userController) { - return userController.currentUserAsync().then(function (user) { - if (user) { - return _ParsePromise2.default.as(user.getSessionToken()); - } - return _ParsePromise2.default.as(null); - }); - } - return _ParsePromise2.default.as(null); - }).then(function (token) { - if (token) { - payload._SessionToken = token; - } - - var payloadString = (0, _stringify2.default)(payload); - - return RESTController.ajax(method, url, payloadString); - }).then(null, function (response) { - // Transform the error into an instance of ParseError by trying to parse - // the error string as JSON - var error; - if (response && response.responseText) { - try { - var errorJSON = JSON.parse(response.responseText); - error = new _ParseError2.default(errorJSON.code, errorJSON.error); - } catch (e) { - // If we fail to parse the error text, that's okay. - error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); - } - } else { - error = new _ParseError2.default(_ParseError2.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify2.default)(response)); - } - - return _ParsePromise2.default.error(error); - }); - }, - _setXHR: function (xhr) { - XHR = xhr; - } -}; - -module.exports = RESTController; -}).call(this,_dereq_('_process')) -},{"./CoreManager":3,"./ParseError":13,"./ParsePromise":20,"./Storage":29,"_process":168,"babel-runtime/core-js/json/stringify":44,"babel-runtime/helpers/typeof":61}],28:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getState = getState; -exports.initializeState = initializeState; -exports.removeState = removeState; -exports.getServerData = getServerData; -exports.setServerData = setServerData; -exports.getPendingOps = getPendingOps; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.getObjectCache = getObjectCache; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; -exports.enqueueTask = enqueueTask; -exports.clearAllState = clearAllState; -exports.duplicateState = duplicateState; - -var _ObjectStateMutations = _dereq_('./ObjectStateMutations'); - -var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -var objectState = {}; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function getState(obj) { - var classData = objectState[obj.className]; - if (classData) { - return classData[obj.id] || null; - } - return null; -} - -function initializeState(obj, initial) { - var state = getState(obj); - if (state) { - return state; - } - if (!objectState[obj.className]) { - objectState[obj.className] = {}; - } - if (!initial) { - initial = ObjectStateMutations.defaultState(); - } - state = objectState[obj.className][obj.id] = initial; - return state; -} - -function removeState(obj) { - var state = getState(obj); - if (state === null) { - return null; - } - delete objectState[obj.className][obj.id]; - return state; -} - -function getServerData(obj) { - var state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -function setServerData(obj, attributes) { - var serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -function getPendingOps(obj) { - var state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -function setPendingOp(obj, attr, op) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -function pushPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -function popPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -function mergeFirstPendingState(obj) { - var pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -function getObjectCache(obj) { - var state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -function estimateAttribute(obj, attr) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -function estimateAttributes(obj) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -function commitServerChanges(obj, changes) { - var state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -function enqueueTask(obj, task) { - var state = initializeState(obj); - return state.tasks.enqueue(task); -} - -function clearAllState() { - objectState = {}; -} - -function duplicateState(source, dest) { - dest.id = source.id; -} -},{"./ObjectStateMutations":9}],29:[function(_dereq_,module,exports){ -'use strict'; - -var _CoreManager = _dereq_('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = { - async: function () { - var controller = _CoreManager2.default.getStorageController(); - return !!controller.async; - }, - getItem: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.getItem(path); - }, - getItemAsync: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.getItemAsync(path); - } - return _ParsePromise2.default.as(controller.getItem(path)); - }, - setItem: function (path, value) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.setItem(path, value); - }, - setItemAsync: function (path, value) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.setItemAsync(path, value); - } - return _ParsePromise2.default.as(controller.setItem(path, value)); - }, - removeItem: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.removeItem(path); - }, - removeItemAsync: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.removeItemAsync(path); - } - return _ParsePromise2.default.as(controller.removeItem(path)); - }, - generatePath: function (path) { - if (!_CoreManager2.default.get('APPLICATION_ID')) { - throw new Error('You need to call Parse.initialize before using Parse.'); - } - if (typeof path !== 'string') { - throw new Error('Tried to get a Storage path that was not a String.'); - } - if (path[0] === '/') { - path = path.substr(1); - } - return 'Parse/' + _CoreManager2.default.get('APPLICATION_ID') + '/' + path; - }, - _clear: function () { - var controller = _CoreManager2.default.getStorageController(); - if (controller.hasOwnProperty('clear')) { - controller.clear(); - } - } -}; - -_CoreManager2.default.setStorageController(_dereq_('./StorageController.browser')); -},{"./CoreManager":3,"./ParsePromise":20,"./StorageController.browser":30}],30:[function(_dereq_,module,exports){ -'use strict'; - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var StorageController = { - async: 0, - - getItem: function (path) { - return localStorage.getItem(path); - }, - setItem: function (path, value) { - try { - localStorage.setItem(path, value); - } catch (e) { - // Quota exceeded, possibly due to Safari Private Browsing mode - } - }, - removeItem: function (path) { - localStorage.removeItem(path); - }, - clear: function () { - localStorage.clear(); - } -}; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = StorageController; -},{"./ParsePromise":20}],31:[function(_dereq_,module,exports){ -'use strict'; - -var _classCallCheck2 = _dereq_('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = _dereq_('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParsePromise = _dereq_('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var TaskQueue = function () { - function TaskQueue() { - (0, _classCallCheck3.default)(this, TaskQueue); - - this.queue = []; - } - - (0, _createClass3.default)(TaskQueue, [{ - key: 'enqueue', - value: function (task) { - var _this = this; - - var taskComplete = new _ParsePromise2.default(); - this.queue.push({ - task: task, - _completion: taskComplete - }); - if (this.queue.length === 1) { - task().then(function () { - _this._dequeue(); - taskComplete.resolve(); - }, function (error) { - _this._dequeue(); - taskComplete.reject(error); - }); - } - return taskComplete; - } - }, { - key: '_dequeue', - value: function () { - var _this2 = this; - - this.queue.shift(); - if (this.queue.length) { - var next = this.queue[0]; - next.task().then(function () { - _this2._dequeue(); - next._completion.resolve(); - }, function (error) { - _this2._dequeue(); - next._completion.reject(error); - }); - } - } - }]); - return TaskQueue; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = TaskQueue; -},{"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],32:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _weakMap = _dereq_('babel-runtime/core-js/weak-map'); - -var _weakMap2 = _interopRequireDefault(_weakMap); - -exports.getState = getState; -exports.initializeState = initializeState; -exports.removeState = removeState; -exports.getServerData = getServerData; -exports.setServerData = setServerData; -exports.getPendingOps = getPendingOps; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.getObjectCache = getObjectCache; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; -exports.enqueueTask = enqueueTask; -exports.duplicateState = duplicateState; -exports.clearAllState = clearAllState; - -var _ObjectStateMutations = _dereq_('./ObjectStateMutations'); - -var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); - -var _TaskQueue = _dereq_('./TaskQueue'); - -var _TaskQueue2 = _interopRequireDefault(_TaskQueue); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var objectState = new _weakMap2.default(); - -function getState(obj) { - var classData = objectState.get(obj); - return classData || null; -} - -function initializeState(obj, initial) { - var state = getState(obj); - if (state) { - return state; - } - if (!initial) { - initial = { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new _TaskQueue2.default(), - existed: false - }; - } - state = initial; - objectState.set(obj, state); - return state; -} - -function removeState(obj) { - var state = getState(obj); - if (state === null) { - return null; - } - objectState.delete(obj); - return state; -} - -function getServerData(obj) { - var state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -function setServerData(obj, attributes) { - var serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -function getPendingOps(obj) { - var state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -function setPendingOp(obj, attr, op) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -function pushPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -function popPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -function mergeFirstPendingState(obj) { - var pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -function getObjectCache(obj) { - var state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -function estimateAttribute(obj, attr) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -function estimateAttributes(obj) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -function commitServerChanges(obj, changes) { - var state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -function enqueueTask(obj, task) { - var state = initializeState(obj); - return state.tasks.enqueue(task); -} - -function duplicateState(source, dest) { - var oldState = initializeState(source); - var newState = initializeState(dest); - for (var key in oldState.serverData) { - newState.serverData[key] = oldState.serverData[key]; - } - for (var index = 0; index < oldState.pendingOps.length; index++) { - for (var _key in oldState.pendingOps[index]) { - newState.pendingOps[index][_key] = oldState.pendingOps[index][_key]; - } - } - for (var _key2 in oldState.objectCache) { - newState.objectCache[_key2] = oldState.objectCache[_key2]; - } - newState.existed = oldState.existed; -} - -function clearAllState() { - objectState = new _weakMap2.default(); -} -},{"./ObjectStateMutations":9,"./TaskQueue":31,"babel-runtime/core-js/weak-map":55}],33:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = arrayContainsObject; - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function arrayContainsObject(array, object) { - if (array.indexOf(object) > -1) { - return true; - } - for (var i = 0; i < array.length; i++) { - if (array[i] instanceof _ParseObject2.default && array[i].className === object.className && array[i]._getId() === object._getId()) { - return true; - } - } - return false; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ -},{"./ParseObject":18}],34:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = canBeSerialized; - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function canBeSerialized(obj) { - if (!(obj instanceof _ParseObject2.default)) { - return true; - } - var attributes = obj.attributes; - for (var attr in attributes) { - var val = attributes[attr]; - if (!canBeSerializedHelper(val)) { - return false; - } - } - return true; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function canBeSerializedHelper(value) { - if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { - return true; - } - if (value instanceof _ParseRelation2.default) { - return true; - } - if (value instanceof _ParseObject2.default) { - return !!value.id; - } - if (value instanceof _ParseFile2.default) { - if (value.url()) { - return true; - } - return false; - } - if (Array.isArray(value)) { - for (var i = 0; i < value.length; i++) { - if (!canBeSerializedHelper(value[i])) { - return false; - } - } - return true; - } - for (var k in value) { - if (!canBeSerializedHelper(value[k])) { - return false; - } - } - return true; -} -},{"./ParseFile":14,"./ParseObject":18,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],35:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = decode; - -var _ParseACL = _dereq_('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseOp = _dereq_('./ParseOp'); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function decode(value) { - if (value === null || (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { - return value; - } - if (Array.isArray(value)) { - var dup = []; - value.forEach(function (v, i) { - dup[i] = decode(v); - }); - return dup; - } - if (typeof value.__op === 'string') { - return (0, _ParseOp.opFromJSON)(value); - } - if (value.__type === 'Pointer' && value.className) { - return _ParseObject2.default.fromJSON(value); - } - if (value.__type === 'Object' && value.className) { - return _ParseObject2.default.fromJSON(value); - } - if (value.__type === 'Relation') { - // The parent and key fields will be populated by the parent - var relation = new _ParseRelation2.default(null, null); - relation.targetClassName = value.className; - return relation; - } - if (value.__type === 'Date') { - return new Date(value.iso); - } - if (value.__type === 'File') { - return _ParseFile2.default.fromJSON(value); - } - if (value.__type === 'GeoPoint') { - return new _ParseGeoPoint2.default({ - latitude: value.latitude, - longitude: value.longitude - }); - } - var copy = {}; - for (var k in value) { - copy[k] = decode(value[k]); - } - return copy; -} -},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"./ParseOp":19,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],36:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _keys = _dereq_('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -exports.default = function (value, disallowObjects, forcePointers, seen) { - return encode(value, !!disallowObjects, !!forcePointers, seen || []); -}; - -var _ParseACL = _dereq_('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseOp = _dereq_('./ParseOp'); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var toString = Object.prototype.toString; - -function encode(value, disallowObjects, forcePointers, seen) { - if (value instanceof _ParseObject2.default) { - if (disallowObjects) { - throw new Error('Parse Objects not allowed here'); - } - var seenEntry = value.id ? value.className + ':' + value.id : value; - if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || (0, _keys2.default)(value._getServerData()).length < 1) { - return value.toPointer(); - } - seen = seen.concat(seenEntry); - return value._toFullJSON(seen); - } - if (value instanceof _ParseOp.Op || value instanceof _ParseACL2.default || value instanceof _ParseGeoPoint2.default || value instanceof _ParseRelation2.default) { - return value.toJSON(); - } - if (value instanceof _ParseFile2.default) { - if (!value.url()) { - throw new Error('Tried to encode an unsaved file.'); - } - return value.toJSON(); - } - if (toString.call(value) === '[object Date]') { - if (isNaN(value)) { - throw new Error('Tried to encode an invalid date.'); - } - return { __type: 'Date', iso: value.toJSON() }; - } - if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { - return value.source; - } - - if (Array.isArray(value)) { - return value.map(function (v) { - return encode(v, disallowObjects, forcePointers, seen); - }); - } - - if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { - var output = {}; - for (var k in value) { - output[k] = encode(value[k], disallowObjects, forcePointers, seen); - } - return output; - } - - return value; -} -},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"./ParseOp":19,"./ParseRelation":22,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],37:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _keys = _dereq_('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = equals; - -var _ParseACL = _dereq_('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = _dereq_('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -function equals(a, b) { - if ((typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== (typeof b === 'undefined' ? 'undefined' : (0, _typeof3.default)(b))) { - return false; - } - - if (!a || (typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== 'object') { - // a is a primitive - return a === b; - } - - if (Array.isArray(a) || Array.isArray(b)) { - if (!Array.isArray(a) || !Array.isArray(b)) { - return false; - } - if (a.length !== b.length) { - return false; - } - for (var i = a.length; i--;) { - if (!equals(a[i], b[i])) { - return false; - } - } - return true; - } - - if (a instanceof _ParseACL2.default || a instanceof _ParseFile2.default || a instanceof _ParseGeoPoint2.default || a instanceof _ParseObject2.default) { - return a.equals(b); - } - - if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) { - return false; - } - for (var k in a) { - if (!equals(a[k], b[k])) { - return false; - } - } - return true; -} -},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],38:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = escape; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var encoded = { - '&': '&', - '<': '<', - '>': '>', - '/': '/', - '\'': ''', - '"': '"' -}; - -function escape(str) { - return str.replace(/[&<>\/'"]/g, function (char) { - return encoded[char]; - }); -} -},{}],39:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = isRevocableSession; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function isRevocableSession(token) { - return token.indexOf('r:') > -1; -} -},{}],40:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = parseDate; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function parseDate(iso8601) { - var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); - var match = regexp.exec(iso8601); - if (!match) { - return null; - } - - var year = match[1] || 0; - var month = (match[2] || 1) - 1; - var day = match[3] || 0; - var hour = match[4] || 0; - var minute = match[5] || 0; - var second = match[6] || 0; - var milli = match[8] || 0; - - return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); -} -},{}],41:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = unique; - -var _arrayContainsObject = _dereq_('./arrayContainsObject'); - -var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function unique(arr) { - var uniques = []; - arr.forEach(function (value) { - if (value instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(uniques, value)) { - uniques.push(value); - } - } else { - if (uniques.indexOf(value) < 0) { - uniques.push(value); - } - } - }); - return uniques; -} -},{"./ParseObject":18,"./arrayContainsObject":33}],42:[function(_dereq_,module,exports){ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = _dereq_('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = unsavedChildren; - -var _ParseFile = _dereq_('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = _dereq_('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = _dereq_('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Return an array of unsaved children, which are either Parse Objects or Files. - * If it encounters any dirty Objects without Ids, it will throw an exception. - */ -function unsavedChildren(obj, allowDeepUnsaved) { - var encountered = { - objects: {}, - files: [] - }; - var identifier = obj.className + ':' + obj._getId(); - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if ((0, _typeof3.default)(attributes[attr]) === 'object') { - traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); - } - } - var unsaved = []; - for (var id in encountered.objects) { - if (id !== identifier && encountered.objects[id] !== true) { - unsaved.push(encountered.objects[id]); - } - } - return unsaved.concat(encountered.files); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { - if (obj instanceof _ParseObject2.default) { - if (!obj.id && shouldThrow) { - throw new Error('Cannot create a pointer to an unsaved Object.'); - } - var identifier = obj.className + ':' + obj._getId(); - if (!encountered.objects[identifier]) { - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if ((0, _typeof3.default)(attributes[attr]) === 'object') { - traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); - } - } - } - return; - } - if (obj instanceof _ParseFile2.default) { - if (!obj.url() && encountered.files.indexOf(obj) < 0) { - encountered.files.push(obj); - } - return; - } - if (obj instanceof _ParseRelation2.default) { - return; - } - if (Array.isArray(obj)) { - obj.forEach(function (el) { - if ((typeof el === 'undefined' ? 'undefined' : (0, _typeof3.default)(el)) === 'object') { - traverse(el, encountered, shouldThrow, allowDeepUnsaved); - } - }); - } - for (var k in obj) { - if ((0, _typeof3.default)(obj[k]) === 'object') { - traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); - } - } -} -},{"./ParseFile":14,"./ParseObject":18,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],43:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/get-iterator"), __esModule: true }; -},{"core-js/library/fn/get-iterator":62}],44:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/json/stringify"), __esModule: true }; -},{"core-js/library/fn/json/stringify":63}],45:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/map"), __esModule: true }; -},{"core-js/library/fn/map":64}],46:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/create"), __esModule: true }; -},{"core-js/library/fn/object/create":65}],47:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/define-property"), __esModule: true }; -},{"core-js/library/fn/object/define-property":66}],48:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/freeze"), __esModule: true }; -},{"core-js/library/fn/object/freeze":67}],49:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/get-own-property-descriptor"), __esModule: true }; -},{"core-js/library/fn/object/get-own-property-descriptor":68}],50:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/get-prototype-of"), __esModule: true }; -},{"core-js/library/fn/object/get-prototype-of":69}],51:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/keys"), __esModule: true }; -},{"core-js/library/fn/object/keys":70}],52:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/object/set-prototype-of"), __esModule: true }; -},{"core-js/library/fn/object/set-prototype-of":71}],53:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/symbol"), __esModule: true }; -},{"core-js/library/fn/symbol":72}],54:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/symbol/iterator"), __esModule: true }; -},{"core-js/library/fn/symbol/iterator":73}],55:[function(_dereq_,module,exports){ -module.exports = { "default": _dereq_("core-js/library/fn/weak-map"), __esModule: true }; -},{"core-js/library/fn/weak-map":74}],56:[function(_dereq_,module,exports){ -"use strict"; - -exports.__esModule = true; - -exports.default = function (instance, Constructor) { - if (!(instance instanceof Constructor)) { - throw new TypeError("Cannot call a class as a function"); - } -}; -},{}],57:[function(_dereq_,module,exports){ -"use strict"; - -exports.__esModule = true; - -var _defineProperty = _dereq_("../core-js/object/define-property"); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function () { - function defineProperties(target, props) { - for (var i = 0; i < props.length; i++) { - var descriptor = props[i]; - descriptor.enumerable = descriptor.enumerable || false; - descriptor.configurable = true; - if ("value" in descriptor) descriptor.writable = true; - (0, _defineProperty2.default)(target, descriptor.key, descriptor); - } - } - - return function (Constructor, protoProps, staticProps) { - if (protoProps) defineProperties(Constructor.prototype, protoProps); - if (staticProps) defineProperties(Constructor, staticProps); - return Constructor; - }; -}(); -},{"../core-js/object/define-property":47}],58:[function(_dereq_,module,exports){ -"use strict"; - -exports.__esModule = true; - -var _getPrototypeOf = _dereq_("../core-js/object/get-prototype-of"); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _getOwnPropertyDescriptor = _dereq_("../core-js/object/get-own-property-descriptor"); - -var _getOwnPropertyDescriptor2 = _interopRequireDefault(_getOwnPropertyDescriptor); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function get(object, property, receiver) { - if (object === null) object = Function.prototype; - var desc = (0, _getOwnPropertyDescriptor2.default)(object, property); - - if (desc === undefined) { - var parent = (0, _getPrototypeOf2.default)(object); - - if (parent === null) { - return undefined; - } else { - return get(parent, property, receiver); - } - } else if ("value" in desc) { - return desc.value; - } else { - var getter = desc.get; - - if (getter === undefined) { - return undefined; - } - - return getter.call(receiver); - } -}; -},{"../core-js/object/get-own-property-descriptor":49,"../core-js/object/get-prototype-of":50}],59:[function(_dereq_,module,exports){ -"use strict"; - -exports.__esModule = true; - -var _setPrototypeOf = _dereq_("../core-js/object/set-prototype-of"); - -var _setPrototypeOf2 = _interopRequireDefault(_setPrototypeOf); - -var _create = _dereq_("../core-js/object/create"); - -var _create2 = _interopRequireDefault(_create); - -var _typeof2 = _dereq_("../helpers/typeof"); - -var _typeof3 = _interopRequireDefault(_typeof2); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function (subClass, superClass) { - if (typeof superClass !== "function" && superClass !== null) { - throw new TypeError("Super expression must either be null or a function, not " + (typeof superClass === "undefined" ? "undefined" : (0, _typeof3.default)(superClass))); - } - - subClass.prototype = (0, _create2.default)(superClass && superClass.prototype, { - constructor: { - value: subClass, - enumerable: false, - writable: true, - configurable: true - } - }); - if (superClass) _setPrototypeOf2.default ? (0, _setPrototypeOf2.default)(subClass, superClass) : subClass.__proto__ = superClass; -}; -},{"../core-js/object/create":46,"../core-js/object/set-prototype-of":52,"../helpers/typeof":61}],60:[function(_dereq_,module,exports){ -"use strict"; - -exports.__esModule = true; - -var _typeof2 = _dereq_("../helpers/typeof"); - -var _typeof3 = _interopRequireDefault(_typeof2); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = function (self, call) { - if (!self) { - throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); - } - - return call && ((typeof call === "undefined" ? "undefined" : (0, _typeof3.default)(call)) === "object" || typeof call === "function") ? call : self; -}; -},{"../helpers/typeof":61}],61:[function(_dereq_,module,exports){ -"use strict"; - -exports.__esModule = true; - -var _iterator = _dereq_("../core-js/symbol/iterator"); - -var _iterator2 = _interopRequireDefault(_iterator); - -var _symbol = _dereq_("../core-js/symbol"); - -var _symbol2 = _interopRequireDefault(_symbol); - -var _typeof = typeof _symbol2.default === "function" && typeof _iterator2.default === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj; }; - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -exports.default = typeof _symbol2.default === "function" && _typeof(_iterator2.default) === "symbol" ? function (obj) { - return typeof obj === "undefined" ? "undefined" : _typeof(obj); -} : function (obj) { - return obj && typeof _symbol2.default === "function" && obj.constructor === _symbol2.default && obj !== _symbol2.default.prototype ? "symbol" : typeof obj === "undefined" ? "undefined" : _typeof(obj); -}; -},{"../core-js/symbol":53,"../core-js/symbol/iterator":54}],62:[function(_dereq_,module,exports){ -_dereq_('../modules/web.dom.iterable'); -_dereq_('../modules/es6.string.iterator'); -module.exports = _dereq_('../modules/core.get-iterator'); -},{"../modules/core.get-iterator":150,"../modules/es6.string.iterator":161,"../modules/web.dom.iterable":167}],63:[function(_dereq_,module,exports){ -var core = _dereq_('../../modules/_core') - , $JSON = core.JSON || (core.JSON = {stringify: JSON.stringify}); -module.exports = function stringify(it){ // eslint-disable-line no-unused-vars - return $JSON.stringify.apply($JSON, arguments); -}; -},{"../../modules/_core":90}],64:[function(_dereq_,module,exports){ -_dereq_('../modules/es6.object.to-string'); -_dereq_('../modules/es6.string.iterator'); -_dereq_('../modules/web.dom.iterable'); -_dereq_('../modules/es6.map'); -_dereq_('../modules/es7.map.to-json'); -module.exports = _dereq_('../modules/_core').Map; -},{"../modules/_core":90,"../modules/es6.map":152,"../modules/es6.object.to-string":160,"../modules/es6.string.iterator":161,"../modules/es7.map.to-json":164,"../modules/web.dom.iterable":167}],65:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.create'); -var $Object = _dereq_('../../modules/_core').Object; -module.exports = function create(P, D){ - return $Object.create(P, D); -}; -},{"../../modules/_core":90,"../../modules/es6.object.create":153}],66:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.define-property'); -var $Object = _dereq_('../../modules/_core').Object; -module.exports = function defineProperty(it, key, desc){ - return $Object.defineProperty(it, key, desc); -}; -},{"../../modules/_core":90,"../../modules/es6.object.define-property":154}],67:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.freeze'); -module.exports = _dereq_('../../modules/_core').Object.freeze; -},{"../../modules/_core":90,"../../modules/es6.object.freeze":155}],68:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.get-own-property-descriptor'); -var $Object = _dereq_('../../modules/_core').Object; -module.exports = function getOwnPropertyDescriptor(it, key){ - return $Object.getOwnPropertyDescriptor(it, key); -}; -},{"../../modules/_core":90,"../../modules/es6.object.get-own-property-descriptor":156}],69:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.get-prototype-of'); -module.exports = _dereq_('../../modules/_core').Object.getPrototypeOf; -},{"../../modules/_core":90,"../../modules/es6.object.get-prototype-of":157}],70:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.keys'); -module.exports = _dereq_('../../modules/_core').Object.keys; -},{"../../modules/_core":90,"../../modules/es6.object.keys":158}],71:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.object.set-prototype-of'); -module.exports = _dereq_('../../modules/_core').Object.setPrototypeOf; -},{"../../modules/_core":90,"../../modules/es6.object.set-prototype-of":159}],72:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.symbol'); -_dereq_('../../modules/es6.object.to-string'); -_dereq_('../../modules/es7.symbol.async-iterator'); -_dereq_('../../modules/es7.symbol.observable'); -module.exports = _dereq_('../../modules/_core').Symbol; -},{"../../modules/_core":90,"../../modules/es6.object.to-string":160,"../../modules/es6.symbol":162,"../../modules/es7.symbol.async-iterator":165,"../../modules/es7.symbol.observable":166}],73:[function(_dereq_,module,exports){ -_dereq_('../../modules/es6.string.iterator'); -_dereq_('../../modules/web.dom.iterable'); -module.exports = _dereq_('../../modules/_wks-ext').f('iterator'); -},{"../../modules/_wks-ext":147,"../../modules/es6.string.iterator":161,"../../modules/web.dom.iterable":167}],74:[function(_dereq_,module,exports){ -_dereq_('../modules/es6.object.to-string'); -_dereq_('../modules/web.dom.iterable'); -_dereq_('../modules/es6.weak-map'); -module.exports = _dereq_('../modules/_core').WeakMap; -},{"../modules/_core":90,"../modules/es6.object.to-string":160,"../modules/es6.weak-map":163,"../modules/web.dom.iterable":167}],75:[function(_dereq_,module,exports){ -module.exports = function(it){ - if(typeof it != 'function')throw TypeError(it + ' is not a function!'); - return it; -}; -},{}],76:[function(_dereq_,module,exports){ -module.exports = function(){ /* empty */ }; -},{}],77:[function(_dereq_,module,exports){ -module.exports = function(it, Constructor, name, forbiddenField){ - if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){ - throw TypeError(name + ': incorrect invocation!'); - } return it; -}; -},{}],78:[function(_dereq_,module,exports){ -var isObject = _dereq_('./_is-object'); -module.exports = function(it){ - if(!isObject(it))throw TypeError(it + ' is not an object!'); - return it; -}; -},{"./_is-object":108}],79:[function(_dereq_,module,exports){ -var forOf = _dereq_('./_for-of'); - -module.exports = function(iter, ITERATOR){ - var result = []; - forOf(iter, false, result.push, result, ITERATOR); - return result; -}; - -},{"./_for-of":99}],80:[function(_dereq_,module,exports){ -// false -> Array#indexOf -// true -> Array#includes -var toIObject = _dereq_('./_to-iobject') - , toLength = _dereq_('./_to-length') - , toIndex = _dereq_('./_to-index'); -module.exports = function(IS_INCLUDES){ - return function($this, el, fromIndex){ - var O = toIObject($this) - , length = toLength(O.length) - , index = toIndex(fromIndex, length) - , value; - // Array#includes uses SameValueZero equality algorithm - if(IS_INCLUDES && el != el)while(length > index){ - value = O[index++]; - if(value != value)return true; - // Array#toIndex ignores holes, Array#includes - not - } else for(;length > index; index++)if(IS_INCLUDES || index in O){ - if(O[index] === el)return IS_INCLUDES || index || 0; - } return !IS_INCLUDES && -1; - }; -}; -},{"./_to-index":139,"./_to-iobject":141,"./_to-length":142}],81:[function(_dereq_,module,exports){ -// 0 -> Array#forEach -// 1 -> Array#map -// 2 -> Array#filter -// 3 -> Array#some -// 4 -> Array#every -// 5 -> Array#find -// 6 -> Array#findIndex -var ctx = _dereq_('./_ctx') - , IObject = _dereq_('./_iobject') - , toObject = _dereq_('./_to-object') - , toLength = _dereq_('./_to-length') - , asc = _dereq_('./_array-species-create'); -module.exports = function(TYPE, $create){ - var IS_MAP = TYPE == 1 - , IS_FILTER = TYPE == 2 - , IS_SOME = TYPE == 3 - , IS_EVERY = TYPE == 4 - , IS_FIND_INDEX = TYPE == 6 - , NO_HOLES = TYPE == 5 || IS_FIND_INDEX - , create = $create || asc; - return function($this, callbackfn, that){ - var O = toObject($this) - , self = IObject(O) - , f = ctx(callbackfn, that, 3) - , length = toLength(self.length) - , index = 0 - , result = IS_MAP ? create($this, length) : IS_FILTER ? create($this, 0) : undefined - , val, res; - for(;length > index; index++)if(NO_HOLES || index in self){ - val = self[index]; - res = f(val, index, O); - if(TYPE){ - if(IS_MAP)result[index] = res; // map - else if(res)switch(TYPE){ - case 3: return true; // some - case 5: return val; // find - case 6: return index; // findIndex - case 2: result.push(val); // filter - } else if(IS_EVERY)return false; // every - } - } - return IS_FIND_INDEX ? -1 : IS_SOME || IS_EVERY ? IS_EVERY : result; - }; -}; -},{"./_array-species-create":83,"./_ctx":91,"./_iobject":105,"./_to-length":142,"./_to-object":143}],82:[function(_dereq_,module,exports){ -var isObject = _dereq_('./_is-object') - , isArray = _dereq_('./_is-array') - , SPECIES = _dereq_('./_wks')('species'); - -module.exports = function(original){ - var C; - if(isArray(original)){ - C = original.constructor; - // cross-realm fallback - if(typeof C == 'function' && (C === Array || isArray(C.prototype)))C = undefined; - if(isObject(C)){ - C = C[SPECIES]; - if(C === null)C = undefined; - } - } return C === undefined ? Array : C; -}; -},{"./_is-array":107,"./_is-object":108,"./_wks":148}],83:[function(_dereq_,module,exports){ -// 9.4.2.3 ArraySpeciesCreate(originalArray, length) -var speciesConstructor = _dereq_('./_array-species-constructor'); - -module.exports = function(original, length){ - return new (speciesConstructor(original))(length); -}; -},{"./_array-species-constructor":82}],84:[function(_dereq_,module,exports){ -// getting tag from 19.1.3.6 Object.prototype.toString() -var cof = _dereq_('./_cof') - , TAG = _dereq_('./_wks')('toStringTag') - // ES3 wrong here - , ARG = cof(function(){ return arguments; }()) == 'Arguments'; - -// fallback for IE11 Script Access Denied error -var tryGet = function(it, key){ - try { - return it[key]; - } catch(e){ /* empty */ } -}; - -module.exports = function(it){ - var O, T, B; - return it === undefined ? 'Undefined' : it === null ? 'Null' - // @@toStringTag case - : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T - // builtinTag case - : ARG ? cof(O) - // ES3 arguments fallback - : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B; -}; -},{"./_cof":85,"./_wks":148}],85:[function(_dereq_,module,exports){ -var toString = {}.toString; - -module.exports = function(it){ - return toString.call(it).slice(8, -1); -}; -},{}],86:[function(_dereq_,module,exports){ -'use strict'; -var dP = _dereq_('./_object-dp').f - , create = _dereq_('./_object-create') - , redefineAll = _dereq_('./_redefine-all') - , ctx = _dereq_('./_ctx') - , anInstance = _dereq_('./_an-instance') - , defined = _dereq_('./_defined') - , forOf = _dereq_('./_for-of') - , $iterDefine = _dereq_('./_iter-define') - , step = _dereq_('./_iter-step') - , setSpecies = _dereq_('./_set-species') - , DESCRIPTORS = _dereq_('./_descriptors') - , fastKey = _dereq_('./_meta').fastKey - , SIZE = DESCRIPTORS ? '_s' : 'size'; - -var getEntry = function(that, key){ - // fast case - var index = fastKey(key), entry; - if(index !== 'F')return that._i[index]; - // frozen object case - for(entry = that._f; entry; entry = entry.n){ - if(entry.k == key)return entry; - } -}; - -module.exports = { - getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ - var C = wrapper(function(that, iterable){ - anInstance(that, C, NAME, '_i'); - that._i = create(null); // index - that._f = undefined; // first entry - that._l = undefined; // last entry - that[SIZE] = 0; // size - if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); - }); - redefineAll(C.prototype, { - // 23.1.3.1 Map.prototype.clear() - // 23.2.3.2 Set.prototype.clear() - clear: function clear(){ - for(var that = this, data = that._i, entry = that._f; entry; entry = entry.n){ - entry.r = true; - if(entry.p)entry.p = entry.p.n = undefined; - delete data[entry.i]; - } - that._f = that._l = undefined; - that[SIZE] = 0; - }, - // 23.1.3.3 Map.prototype.delete(key) - // 23.2.3.4 Set.prototype.delete(value) - 'delete': function(key){ - var that = this - , entry = getEntry(that, key); - if(entry){ - var next = entry.n - , prev = entry.p; - delete that._i[entry.i]; - entry.r = true; - if(prev)prev.n = next; - if(next)next.p = prev; - if(that._f == entry)that._f = next; - if(that._l == entry)that._l = prev; - that[SIZE]--; - } return !!entry; - }, - // 23.2.3.6 Set.prototype.forEach(callbackfn, thisArg = undefined) - // 23.1.3.5 Map.prototype.forEach(callbackfn, thisArg = undefined) - forEach: function forEach(callbackfn /*, that = undefined */){ - anInstance(this, C, 'forEach'); - var f = ctx(callbackfn, arguments.length > 1 ? arguments[1] : undefined, 3) - , entry; - while(entry = entry ? entry.n : this._f){ - f(entry.v, entry.k, this); - // revert to the last existing entry - while(entry && entry.r)entry = entry.p; - } - }, - // 23.1.3.7 Map.prototype.has(key) - // 23.2.3.7 Set.prototype.has(value) - has: function has(key){ - return !!getEntry(this, key); - } - }); - if(DESCRIPTORS)dP(C.prototype, 'size', { - get: function(){ - return defined(this[SIZE]); - } - }); - return C; - }, - def: function(that, key, value){ - var entry = getEntry(that, key) - , prev, index; - // change existing entry - if(entry){ - entry.v = value; - // create new entry - } else { - that._l = entry = { - i: index = fastKey(key, true), // <- index - k: key, // <- key - v: value, // <- value - p: prev = that._l, // <- previous entry - n: undefined, // <- next entry - r: false // <- removed - }; - if(!that._f)that._f = entry; - if(prev)prev.n = entry; - that[SIZE]++; - // add to index - if(index !== 'F')that._i[index] = entry; - } return that; - }, - getEntry: getEntry, - setStrong: function(C, NAME, IS_MAP){ - // add .keys, .values, .entries, [@@iterator] - // 23.1.3.4, 23.1.3.8, 23.1.3.11, 23.1.3.12, 23.2.3.5, 23.2.3.8, 23.2.3.10, 23.2.3.11 - $iterDefine(C, NAME, function(iterated, kind){ - this._t = iterated; // target - this._k = kind; // kind - this._l = undefined; // previous - }, function(){ - var that = this - , kind = that._k - , entry = that._l; - // revert to the last existing entry - while(entry && entry.r)entry = entry.p; - // get next entry - if(!that._t || !(that._l = entry = entry ? entry.n : that._t._f)){ - // or finish the iteration - that._t = undefined; - return step(1); - } - // return step by kind - if(kind == 'keys' )return step(0, entry.k); - if(kind == 'values')return step(0, entry.v); - return step(0, [entry.k, entry.v]); - }, IS_MAP ? 'entries' : 'values' , !IS_MAP, true); - - // add [@@species], 23.1.2.2, 23.2.2.2 - setSpecies(NAME); - } -}; -},{"./_an-instance":77,"./_ctx":91,"./_defined":92,"./_descriptors":93,"./_for-of":99,"./_iter-define":111,"./_iter-step":112,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_redefine-all":131,"./_set-species":134}],87:[function(_dereq_,module,exports){ -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var classof = _dereq_('./_classof') - , from = _dereq_('./_array-from-iterable'); -module.exports = function(NAME){ - return function toJSON(){ - if(classof(this) != NAME)throw TypeError(NAME + "#toJSON isn't generic"); - return from(this); - }; -}; -},{"./_array-from-iterable":79,"./_classof":84}],88:[function(_dereq_,module,exports){ -'use strict'; -var redefineAll = _dereq_('./_redefine-all') - , getWeak = _dereq_('./_meta').getWeak - , anObject = _dereq_('./_an-object') - , isObject = _dereq_('./_is-object') - , anInstance = _dereq_('./_an-instance') - , forOf = _dereq_('./_for-of') - , createArrayMethod = _dereq_('./_array-methods') - , $has = _dereq_('./_has') - , arrayFind = createArrayMethod(5) - , arrayFindIndex = createArrayMethod(6) - , id = 0; - -// fallback for uncaught frozen keys -var uncaughtFrozenStore = function(that){ - return that._l || (that._l = new UncaughtFrozenStore); -}; -var UncaughtFrozenStore = function(){ - this.a = []; -}; -var findUncaughtFrozen = function(store, key){ - return arrayFind(store.a, function(it){ - return it[0] === key; - }); -}; -UncaughtFrozenStore.prototype = { - get: function(key){ - var entry = findUncaughtFrozen(this, key); - if(entry)return entry[1]; - }, - has: function(key){ - return !!findUncaughtFrozen(this, key); - }, - set: function(key, value){ - var entry = findUncaughtFrozen(this, key); - if(entry)entry[1] = value; - else this.a.push([key, value]); - }, - 'delete': function(key){ - var index = arrayFindIndex(this.a, function(it){ - return it[0] === key; - }); - if(~index)this.a.splice(index, 1); - return !!~index; - } -}; - -module.exports = { - getConstructor: function(wrapper, NAME, IS_MAP, ADDER){ - var C = wrapper(function(that, iterable){ - anInstance(that, C, NAME, '_i'); - that._i = id++; // collection id - that._l = undefined; // leak store for uncaught frozen objects - if(iterable != undefined)forOf(iterable, IS_MAP, that[ADDER], that); - }); - redefineAll(C.prototype, { - // 23.3.3.2 WeakMap.prototype.delete(key) - // 23.4.3.3 WeakSet.prototype.delete(value) - 'delete': function(key){ - if(!isObject(key))return false; - var data = getWeak(key); - if(data === true)return uncaughtFrozenStore(this)['delete'](key); - return data && $has(data, this._i) && delete data[this._i]; - }, - // 23.3.3.4 WeakMap.prototype.has(key) - // 23.4.3.4 WeakSet.prototype.has(value) - has: function has(key){ - if(!isObject(key))return false; - var data = getWeak(key); - if(data === true)return uncaughtFrozenStore(this).has(key); - return data && $has(data, this._i); - } - }); - return C; - }, - def: function(that, key, value){ - var data = getWeak(anObject(key), true); - if(data === true)uncaughtFrozenStore(that).set(key, value); - else data[that._i] = value; - return that; - }, - ufstore: uncaughtFrozenStore -}; -},{"./_an-instance":77,"./_an-object":78,"./_array-methods":81,"./_for-of":99,"./_has":101,"./_is-object":108,"./_meta":116,"./_redefine-all":131}],89:[function(_dereq_,module,exports){ -'use strict'; -var global = _dereq_('./_global') - , $export = _dereq_('./_export') - , meta = _dereq_('./_meta') - , fails = _dereq_('./_fails') - , hide = _dereq_('./_hide') - , redefineAll = _dereq_('./_redefine-all') - , forOf = _dereq_('./_for-of') - , anInstance = _dereq_('./_an-instance') - , isObject = _dereq_('./_is-object') - , setToStringTag = _dereq_('./_set-to-string-tag') - , dP = _dereq_('./_object-dp').f - , each = _dereq_('./_array-methods')(0) - , DESCRIPTORS = _dereq_('./_descriptors'); - -module.exports = function(NAME, wrapper, methods, common, IS_MAP, IS_WEAK){ - var Base = global[NAME] - , C = Base - , ADDER = IS_MAP ? 'set' : 'add' - , proto = C && C.prototype - , O = {}; - if(!DESCRIPTORS || typeof C != 'function' || !(IS_WEAK || proto.forEach && !fails(function(){ - new C().entries().next(); - }))){ - // create collection constructor - C = common.getConstructor(wrapper, NAME, IS_MAP, ADDER); - redefineAll(C.prototype, methods); - meta.NEED = true; - } else { - C = wrapper(function(target, iterable){ - anInstance(target, C, NAME, '_c'); - target._c = new Base; - if(iterable != undefined)forOf(iterable, IS_MAP, target[ADDER], target); - }); - each('add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON'.split(','),function(KEY){ - var IS_ADDER = KEY == 'add' || KEY == 'set'; - if(KEY in proto && !(IS_WEAK && KEY == 'clear'))hide(C.prototype, KEY, function(a, b){ - anInstance(this, C, KEY); - if(!IS_ADDER && IS_WEAK && !isObject(a))return KEY == 'get' ? undefined : false; - var result = this._c[KEY](a === 0 ? 0 : a, b); - return IS_ADDER ? this : result; - }); - }); - if('size' in proto)dP(C.prototype, 'size', { - get: function(){ - return this._c.size; - } - }); - } - - setToStringTag(C, NAME); - - O[NAME] = C; - $export($export.G + $export.W + $export.F, O); - - if(!IS_WEAK)common.setStrong(C, NAME, IS_MAP); - - return C; -}; -},{"./_an-instance":77,"./_array-methods":81,"./_descriptors":93,"./_export":97,"./_fails":98,"./_for-of":99,"./_global":100,"./_hide":102,"./_is-object":108,"./_meta":116,"./_object-dp":119,"./_redefine-all":131,"./_set-to-string-tag":135}],90:[function(_dereq_,module,exports){ -var core = module.exports = {version: '2.4.0'}; -if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef -},{}],91:[function(_dereq_,module,exports){ -// optional / simple context binding -var aFunction = _dereq_('./_a-function'); -module.exports = function(fn, that, length){ - aFunction(fn); - if(that === undefined)return fn; - switch(length){ - case 1: return function(a){ - return fn.call(that, a); - }; - case 2: return function(a, b){ - return fn.call(that, a, b); - }; - case 3: return function(a, b, c){ - return fn.call(that, a, b, c); - }; - } - return function(/* ...args */){ - return fn.apply(that, arguments); - }; -}; -},{"./_a-function":75}],92:[function(_dereq_,module,exports){ -// 7.2.1 RequireObjectCoercible(argument) -module.exports = function(it){ - if(it == undefined)throw TypeError("Can't call method on " + it); - return it; -}; -},{}],93:[function(_dereq_,module,exports){ -// Thank's IE8 for his funny defineProperty -module.exports = !_dereq_('./_fails')(function(){ - return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7; -}); -},{"./_fails":98}],94:[function(_dereq_,module,exports){ -var isObject = _dereq_('./_is-object') - , document = _dereq_('./_global').document - // in old IE typeof document.createElement is 'object' - , is = isObject(document) && isObject(document.createElement); -module.exports = function(it){ - return is ? document.createElement(it) : {}; -}; -},{"./_global":100,"./_is-object":108}],95:[function(_dereq_,module,exports){ -// IE 8- don't enum bug keys -module.exports = ( - 'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf' -).split(','); -},{}],96:[function(_dereq_,module,exports){ -// all enumerable object keys, includes symbols -var getKeys = _dereq_('./_object-keys') - , gOPS = _dereq_('./_object-gops') - , pIE = _dereq_('./_object-pie'); -module.exports = function(it){ - var result = getKeys(it) - , getSymbols = gOPS.f; - if(getSymbols){ - var symbols = getSymbols(it) - , isEnum = pIE.f - , i = 0 - , key; - while(symbols.length > i)if(isEnum.call(it, key = symbols[i++]))result.push(key); - } return result; -}; -},{"./_object-gops":124,"./_object-keys":127,"./_object-pie":128}],97:[function(_dereq_,module,exports){ -var global = _dereq_('./_global') - , core = _dereq_('./_core') - , ctx = _dereq_('./_ctx') - , hide = _dereq_('./_hide') - , PROTOTYPE = 'prototype'; - -var $export = function(type, name, source){ - var IS_FORCED = type & $export.F - , IS_GLOBAL = type & $export.G - , IS_STATIC = type & $export.S - , IS_PROTO = type & $export.P - , IS_BIND = type & $export.B - , IS_WRAP = type & $export.W - , exports = IS_GLOBAL ? core : core[name] || (core[name] = {}) - , expProto = exports[PROTOTYPE] - , target = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE] - , key, own, out; - if(IS_GLOBAL)source = name; - for(key in source){ - // contains in native - own = !IS_FORCED && target && target[key] !== undefined; - if(own && key in exports)continue; - // export native or passed - out = own ? target[key] : source[key]; - // prevent global pollution for namespaces - exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key] - // bind timers to global for call from export context - : IS_BIND && own ? ctx(out, global) - // wrap global constructors for prevent change them in library - : IS_WRAP && target[key] == out ? (function(C){ - var F = function(a, b, c){ - if(this instanceof C){ - switch(arguments.length){ - case 0: return new C; - case 1: return new C(a); - case 2: return new C(a, b); - } return new C(a, b, c); - } return C.apply(this, arguments); - }; - F[PROTOTYPE] = C[PROTOTYPE]; - return F; - // make static versions for prototype methods - })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out; - // export proto methods to core.%CONSTRUCTOR%.methods.%NAME% - if(IS_PROTO){ - (exports.virtual || (exports.virtual = {}))[key] = out; - // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME% - if(type & $export.R && expProto && !expProto[key])hide(expProto, key, out); - } - } -}; -// type bitmap -$export.F = 1; // forced -$export.G = 2; // global -$export.S = 4; // static -$export.P = 8; // proto -$export.B = 16; // bind -$export.W = 32; // wrap -$export.U = 64; // safe -$export.R = 128; // real proto method for `library` -module.exports = $export; -},{"./_core":90,"./_ctx":91,"./_global":100,"./_hide":102}],98:[function(_dereq_,module,exports){ -module.exports = function(exec){ - try { - return !!exec(); - } catch(e){ - return true; - } -}; -},{}],99:[function(_dereq_,module,exports){ -var ctx = _dereq_('./_ctx') - , call = _dereq_('./_iter-call') - , isArrayIter = _dereq_('./_is-array-iter') - , anObject = _dereq_('./_an-object') - , toLength = _dereq_('./_to-length') - , getIterFn = _dereq_('./core.get-iterator-method') - , BREAK = {} - , RETURN = {}; -var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){ - var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable) - , f = ctx(fn, that, entries ? 2 : 1) - , index = 0 - , length, step, iterator, result; - if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!'); - // fast case for arrays with default iterator - if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){ - result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]); - if(result === BREAK || result === RETURN)return result; - } else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){ - result = call(iterator, f, step.value, entries); - if(result === BREAK || result === RETURN)return result; - } -}; -exports.BREAK = BREAK; -exports.RETURN = RETURN; -},{"./_an-object":78,"./_ctx":91,"./_is-array-iter":106,"./_iter-call":109,"./_to-length":142,"./core.get-iterator-method":149}],100:[function(_dereq_,module,exports){ -// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028 -var global = module.exports = typeof window != 'undefined' && window.Math == Math - ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')(); -if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef -},{}],101:[function(_dereq_,module,exports){ -var hasOwnProperty = {}.hasOwnProperty; -module.exports = function(it, key){ - return hasOwnProperty.call(it, key); -}; -},{}],102:[function(_dereq_,module,exports){ -var dP = _dereq_('./_object-dp') - , createDesc = _dereq_('./_property-desc'); -module.exports = _dereq_('./_descriptors') ? function(object, key, value){ - return dP.f(object, key, createDesc(1, value)); -} : function(object, key, value){ - object[key] = value; - return object; -}; -},{"./_descriptors":93,"./_object-dp":119,"./_property-desc":130}],103:[function(_dereq_,module,exports){ -module.exports = _dereq_('./_global').document && document.documentElement; -},{"./_global":100}],104:[function(_dereq_,module,exports){ -module.exports = !_dereq_('./_descriptors') && !_dereq_('./_fails')(function(){ - return Object.defineProperty(_dereq_('./_dom-create')('div'), 'a', {get: function(){ return 7; }}).a != 7; -}); -},{"./_descriptors":93,"./_dom-create":94,"./_fails":98}],105:[function(_dereq_,module,exports){ -// fallback for non-array-like ES3 and non-enumerable old V8 strings -var cof = _dereq_('./_cof'); -module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){ - return cof(it) == 'String' ? it.split('') : Object(it); -}; -},{"./_cof":85}],106:[function(_dereq_,module,exports){ -// check on default Array iterator -var Iterators = _dereq_('./_iterators') - , ITERATOR = _dereq_('./_wks')('iterator') - , ArrayProto = Array.prototype; - -module.exports = function(it){ - return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it); -}; -},{"./_iterators":113,"./_wks":148}],107:[function(_dereq_,module,exports){ -// 7.2.2 IsArray(argument) -var cof = _dereq_('./_cof'); -module.exports = Array.isArray || function isArray(arg){ - return cof(arg) == 'Array'; -}; -},{"./_cof":85}],108:[function(_dereq_,module,exports){ -module.exports = function(it){ - return typeof it === 'object' ? it !== null : typeof it === 'function'; -}; -},{}],109:[function(_dereq_,module,exports){ -// call something on iterator step with safe closing on error -var anObject = _dereq_('./_an-object'); -module.exports = function(iterator, fn, value, entries){ - try { - return entries ? fn(anObject(value)[0], value[1]) : fn(value); - // 7.4.6 IteratorClose(iterator, completion) - } catch(e){ - var ret = iterator['return']; - if(ret !== undefined)anObject(ret.call(iterator)); - throw e; - } -}; -},{"./_an-object":78}],110:[function(_dereq_,module,exports){ -'use strict'; -var create = _dereq_('./_object-create') - , descriptor = _dereq_('./_property-desc') - , setToStringTag = _dereq_('./_set-to-string-tag') - , IteratorPrototype = {}; - -// 25.1.2.1.1 %IteratorPrototype%[@@iterator]() -_dereq_('./_hide')(IteratorPrototype, _dereq_('./_wks')('iterator'), function(){ return this; }); - -module.exports = function(Constructor, NAME, next){ - Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)}); - setToStringTag(Constructor, NAME + ' Iterator'); -}; -},{"./_hide":102,"./_object-create":118,"./_property-desc":130,"./_set-to-string-tag":135,"./_wks":148}],111:[function(_dereq_,module,exports){ -'use strict'; -var LIBRARY = _dereq_('./_library') - , $export = _dereq_('./_export') - , redefine = _dereq_('./_redefine') - , hide = _dereq_('./_hide') - , has = _dereq_('./_has') - , Iterators = _dereq_('./_iterators') - , $iterCreate = _dereq_('./_iter-create') - , setToStringTag = _dereq_('./_set-to-string-tag') - , getPrototypeOf = _dereq_('./_object-gpo') - , ITERATOR = _dereq_('./_wks')('iterator') - , BUGGY = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next` - , FF_ITERATOR = '@@iterator' - , KEYS = 'keys' - , VALUES = 'values'; - -var returnThis = function(){ return this; }; - -module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){ - $iterCreate(Constructor, NAME, next); - var getMethod = function(kind){ - if(!BUGGY && kind in proto)return proto[kind]; - switch(kind){ - case KEYS: return function keys(){ return new Constructor(this, kind); }; - case VALUES: return function values(){ return new Constructor(this, kind); }; - } return function entries(){ return new Constructor(this, kind); }; - }; - var TAG = NAME + ' Iterator' - , DEF_VALUES = DEFAULT == VALUES - , VALUES_BUG = false - , proto = Base.prototype - , $native = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT] - , $default = $native || getMethod(DEFAULT) - , $entries = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined - , $anyNative = NAME == 'Array' ? proto.entries || $native : $native - , methods, key, IteratorPrototype; - // Fix native - if($anyNative){ - IteratorPrototype = getPrototypeOf($anyNative.call(new Base)); - if(IteratorPrototype !== Object.prototype){ - // Set @@toStringTag to native iterators - setToStringTag(IteratorPrototype, TAG, true); - // fix for some old engines - if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis); - } - } - // fix Array#{values, @@iterator}.name in V8 / FF - if(DEF_VALUES && $native && $native.name !== VALUES){ - VALUES_BUG = true; - $default = function values(){ return $native.call(this); }; - } - // Define iterator - if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){ - hide(proto, ITERATOR, $default); - } - // Plug for library - Iterators[NAME] = $default; - Iterators[TAG] = returnThis; - if(DEFAULT){ - methods = { - values: DEF_VALUES ? $default : getMethod(VALUES), - keys: IS_SET ? $default : getMethod(KEYS), - entries: $entries - }; - if(FORCED)for(key in methods){ - if(!(key in proto))redefine(proto, key, methods[key]); - } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods); - } - return methods; -}; -},{"./_export":97,"./_has":101,"./_hide":102,"./_iter-create":110,"./_iterators":113,"./_library":115,"./_object-gpo":125,"./_redefine":132,"./_set-to-string-tag":135,"./_wks":148}],112:[function(_dereq_,module,exports){ -module.exports = function(done, value){ - return {value: value, done: !!done}; -}; -},{}],113:[function(_dereq_,module,exports){ -module.exports = {}; -},{}],114:[function(_dereq_,module,exports){ -var getKeys = _dereq_('./_object-keys') - , toIObject = _dereq_('./_to-iobject'); -module.exports = function(object, el){ - var O = toIObject(object) - , keys = getKeys(O) - , length = keys.length - , index = 0 - , key; - while(length > index)if(O[key = keys[index++]] === el)return key; -}; -},{"./_object-keys":127,"./_to-iobject":141}],115:[function(_dereq_,module,exports){ -module.exports = true; -},{}],116:[function(_dereq_,module,exports){ -var META = _dereq_('./_uid')('meta') - , isObject = _dereq_('./_is-object') - , has = _dereq_('./_has') - , setDesc = _dereq_('./_object-dp').f - , id = 0; -var isExtensible = Object.isExtensible || function(){ - return true; -}; -var FREEZE = !_dereq_('./_fails')(function(){ - return isExtensible(Object.preventExtensions({})); -}); -var setMeta = function(it){ - setDesc(it, META, {value: { - i: 'O' + ++id, // object ID - w: {} // weak collections IDs - }}); -}; -var fastKey = function(it, create){ - // return primitive with prefix - if(!isObject(it))return typeof it == 'symbol' ? it : (typeof it == 'string' ? 'S' : 'P') + it; - if(!has(it, META)){ - // can't set metadata to uncaught frozen object - if(!isExtensible(it))return 'F'; - // not necessary to add metadata - if(!create)return 'E'; - // add missing metadata - setMeta(it); - // return object ID - } return it[META].i; -}; -var getWeak = function(it, create){ - if(!has(it, META)){ - // can't set metadata to uncaught frozen object - if(!isExtensible(it))return true; - // not necessary to add metadata - if(!create)return false; - // add missing metadata - setMeta(it); - // return hash weak collections IDs - } return it[META].w; -}; -// add metadata on freeze-family methods calling -var onFreeze = function(it){ - if(FREEZE && meta.NEED && isExtensible(it) && !has(it, META))setMeta(it); - return it; -}; -var meta = module.exports = { - KEY: META, - NEED: false, - fastKey: fastKey, - getWeak: getWeak, - onFreeze: onFreeze -}; -},{"./_fails":98,"./_has":101,"./_is-object":108,"./_object-dp":119,"./_uid":145}],117:[function(_dereq_,module,exports){ -'use strict'; -// 19.1.2.1 Object.assign(target, source, ...) -var getKeys = _dereq_('./_object-keys') - , gOPS = _dereq_('./_object-gops') - , pIE = _dereq_('./_object-pie') - , toObject = _dereq_('./_to-object') - , IObject = _dereq_('./_iobject') - , $assign = Object.assign; - -// should work with symbols and should have deterministic property order (V8 bug) -module.exports = !$assign || _dereq_('./_fails')(function(){ - var A = {} - , B = {} - , S = Symbol() - , K = 'abcdefghijklmnopqrst'; - A[S] = 7; - K.split('').forEach(function(k){ B[k] = k; }); - return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K; -}) ? function assign(target, source){ // eslint-disable-line no-unused-vars - var T = toObject(target) - , aLen = arguments.length - , index = 1 - , getSymbols = gOPS.f - , isEnum = pIE.f; - while(aLen > index){ - var S = IObject(arguments[index++]) - , keys = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S) - , length = keys.length - , j = 0 - , key; - while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key]; - } return T; -} : $assign; -},{"./_fails":98,"./_iobject":105,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_to-object":143}],118:[function(_dereq_,module,exports){ -// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) -var anObject = _dereq_('./_an-object') - , dPs = _dereq_('./_object-dps') - , enumBugKeys = _dereq_('./_enum-bug-keys') - , IE_PROTO = _dereq_('./_shared-key')('IE_PROTO') - , Empty = function(){ /* empty */ } - , PROTOTYPE = 'prototype'; - -// Create object with fake `null` prototype: use iframe Object with cleared prototype -var createDict = function(){ - // Thrash, waste and sodomy: IE GC bug - var iframe = _dereq_('./_dom-create')('iframe') - , i = enumBugKeys.length - , lt = '<' - , gt = '>' - , iframeDocument; - iframe.style.display = 'none'; - _dereq_('./_html').appendChild(iframe); - iframe.src = 'javascript:'; // eslint-disable-line no-script-url - // createDict = iframe.contentWindow.Object; - // html.removeChild(iframe); - iframeDocument = iframe.contentWindow.document; - iframeDocument.open(); - iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt); - iframeDocument.close(); - createDict = iframeDocument.F; - while(i--)delete createDict[PROTOTYPE][enumBugKeys[i]]; - return createDict(); -}; - -module.exports = Object.create || function create(O, Properties){ - var result; - if(O !== null){ - Empty[PROTOTYPE] = anObject(O); - result = new Empty; - Empty[PROTOTYPE] = null; - // add "__proto__" for Object.getPrototypeOf polyfill - result[IE_PROTO] = O; - } else result = createDict(); - return Properties === undefined ? result : dPs(result, Properties); -}; - -},{"./_an-object":78,"./_dom-create":94,"./_enum-bug-keys":95,"./_html":103,"./_object-dps":120,"./_shared-key":136}],119:[function(_dereq_,module,exports){ -var anObject = _dereq_('./_an-object') - , IE8_DOM_DEFINE = _dereq_('./_ie8-dom-define') - , toPrimitive = _dereq_('./_to-primitive') - , dP = Object.defineProperty; - -exports.f = _dereq_('./_descriptors') ? Object.defineProperty : function defineProperty(O, P, Attributes){ - anObject(O); - P = toPrimitive(P, true); - anObject(Attributes); - if(IE8_DOM_DEFINE)try { - return dP(O, P, Attributes); - } catch(e){ /* empty */ } - if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!'); - if('value' in Attributes)O[P] = Attributes.value; - return O; -}; -},{"./_an-object":78,"./_descriptors":93,"./_ie8-dom-define":104,"./_to-primitive":144}],120:[function(_dereq_,module,exports){ -var dP = _dereq_('./_object-dp') - , anObject = _dereq_('./_an-object') - , getKeys = _dereq_('./_object-keys'); - -module.exports = _dereq_('./_descriptors') ? Object.defineProperties : function defineProperties(O, Properties){ - anObject(O); - var keys = getKeys(Properties) - , length = keys.length - , i = 0 - , P; - while(length > i)dP.f(O, P = keys[i++], Properties[P]); - return O; -}; -},{"./_an-object":78,"./_descriptors":93,"./_object-dp":119,"./_object-keys":127}],121:[function(_dereq_,module,exports){ -var pIE = _dereq_('./_object-pie') - , createDesc = _dereq_('./_property-desc') - , toIObject = _dereq_('./_to-iobject') - , toPrimitive = _dereq_('./_to-primitive') - , has = _dereq_('./_has') - , IE8_DOM_DEFINE = _dereq_('./_ie8-dom-define') - , gOPD = Object.getOwnPropertyDescriptor; - -exports.f = _dereq_('./_descriptors') ? gOPD : function getOwnPropertyDescriptor(O, P){ - O = toIObject(O); - P = toPrimitive(P, true); - if(IE8_DOM_DEFINE)try { - return gOPD(O, P); - } catch(e){ /* empty */ } - if(has(O, P))return createDesc(!pIE.f.call(O, P), O[P]); -}; -},{"./_descriptors":93,"./_has":101,"./_ie8-dom-define":104,"./_object-pie":128,"./_property-desc":130,"./_to-iobject":141,"./_to-primitive":144}],122:[function(_dereq_,module,exports){ -// fallback for IE11 buggy Object.getOwnPropertyNames with iframe and window -var toIObject = _dereq_('./_to-iobject') - , gOPN = _dereq_('./_object-gopn').f - , toString = {}.toString; - -var windowNames = typeof window == 'object' && window && Object.getOwnPropertyNames - ? Object.getOwnPropertyNames(window) : []; - -var getWindowNames = function(it){ - try { - return gOPN(it); - } catch(e){ - return windowNames.slice(); - } -}; - -module.exports.f = function getOwnPropertyNames(it){ - return windowNames && toString.call(it) == '[object Window]' ? getWindowNames(it) : gOPN(toIObject(it)); -}; - -},{"./_object-gopn":123,"./_to-iobject":141}],123:[function(_dereq_,module,exports){ -// 19.1.2.7 / 15.2.3.4 Object.getOwnPropertyNames(O) -var $keys = _dereq_('./_object-keys-internal') - , hiddenKeys = _dereq_('./_enum-bug-keys').concat('length', 'prototype'); - -exports.f = Object.getOwnPropertyNames || function getOwnPropertyNames(O){ - return $keys(O, hiddenKeys); -}; -},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],124:[function(_dereq_,module,exports){ -exports.f = Object.getOwnPropertySymbols; -},{}],125:[function(_dereq_,module,exports){ -// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O) -var has = _dereq_('./_has') - , toObject = _dereq_('./_to-object') - , IE_PROTO = _dereq_('./_shared-key')('IE_PROTO') - , ObjectProto = Object.prototype; - -module.exports = Object.getPrototypeOf || function(O){ - O = toObject(O); - if(has(O, IE_PROTO))return O[IE_PROTO]; - if(typeof O.constructor == 'function' && O instanceof O.constructor){ - return O.constructor.prototype; - } return O instanceof Object ? ObjectProto : null; -}; -},{"./_has":101,"./_shared-key":136,"./_to-object":143}],126:[function(_dereq_,module,exports){ -var has = _dereq_('./_has') - , toIObject = _dereq_('./_to-iobject') - , arrayIndexOf = _dereq_('./_array-includes')(false) - , IE_PROTO = _dereq_('./_shared-key')('IE_PROTO'); - -module.exports = function(object, names){ - var O = toIObject(object) - , i = 0 - , result = [] - , key; - for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key); - // Don't enum bug & hidden keys - while(names.length > i)if(has(O, key = names[i++])){ - ~arrayIndexOf(result, key) || result.push(key); - } - return result; -}; -},{"./_array-includes":80,"./_has":101,"./_shared-key":136,"./_to-iobject":141}],127:[function(_dereq_,module,exports){ -// 19.1.2.14 / 15.2.3.14 Object.keys(O) -var $keys = _dereq_('./_object-keys-internal') - , enumBugKeys = _dereq_('./_enum-bug-keys'); - -module.exports = Object.keys || function keys(O){ - return $keys(O, enumBugKeys); -}; -},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],128:[function(_dereq_,module,exports){ -exports.f = {}.propertyIsEnumerable; -},{}],129:[function(_dereq_,module,exports){ -// most Object methods by ES6 should accept primitives -var $export = _dereq_('./_export') - , core = _dereq_('./_core') - , fails = _dereq_('./_fails'); -module.exports = function(KEY, exec){ - var fn = (core.Object || {})[KEY] || Object[KEY] - , exp = {}; - exp[KEY] = exec(fn); - $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp); -}; -},{"./_core":90,"./_export":97,"./_fails":98}],130:[function(_dereq_,module,exports){ -module.exports = function(bitmap, value){ - return { - enumerable : !(bitmap & 1), - configurable: !(bitmap & 2), - writable : !(bitmap & 4), - value : value - }; -}; -},{}],131:[function(_dereq_,module,exports){ -var hide = _dereq_('./_hide'); -module.exports = function(target, src, safe){ - for(var key in src){ - if(safe && target[key])target[key] = src[key]; - else hide(target, key, src[key]); - } return target; -}; -},{"./_hide":102}],132:[function(_dereq_,module,exports){ -module.exports = _dereq_('./_hide'); -},{"./_hide":102}],133:[function(_dereq_,module,exports){ -// Works with __proto__ only. Old v8 can't work with null proto objects. -/* eslint-disable no-proto */ -var isObject = _dereq_('./_is-object') - , anObject = _dereq_('./_an-object'); -var check = function(O, proto){ - anObject(O); - if(!isObject(proto) && proto !== null)throw TypeError(proto + ": can't set as prototype!"); -}; -module.exports = { - set: Object.setPrototypeOf || ('__proto__' in {} ? // eslint-disable-line - function(test, buggy, set){ - try { - set = _dereq_('./_ctx')(Function.call, _dereq_('./_object-gopd').f(Object.prototype, '__proto__').set, 2); - set(test, []); - buggy = !(test instanceof Array); - } catch(e){ buggy = true; } - return function setPrototypeOf(O, proto){ - check(O, proto); - if(buggy)O.__proto__ = proto; - else set(O, proto); - return O; - }; - }({}, false) : undefined), - check: check -}; -},{"./_an-object":78,"./_ctx":91,"./_is-object":108,"./_object-gopd":121}],134:[function(_dereq_,module,exports){ -'use strict'; -var global = _dereq_('./_global') - , core = _dereq_('./_core') - , dP = _dereq_('./_object-dp') - , DESCRIPTORS = _dereq_('./_descriptors') - , SPECIES = _dereq_('./_wks')('species'); - -module.exports = function(KEY){ - var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY]; - if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, { - configurable: true, - get: function(){ return this; } - }); -}; -},{"./_core":90,"./_descriptors":93,"./_global":100,"./_object-dp":119,"./_wks":148}],135:[function(_dereq_,module,exports){ -var def = _dereq_('./_object-dp').f - , has = _dereq_('./_has') - , TAG = _dereq_('./_wks')('toStringTag'); - -module.exports = function(it, tag, stat){ - if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag}); -}; -},{"./_has":101,"./_object-dp":119,"./_wks":148}],136:[function(_dereq_,module,exports){ -var shared = _dereq_('./_shared')('keys') - , uid = _dereq_('./_uid'); -module.exports = function(key){ - return shared[key] || (shared[key] = uid(key)); -}; -},{"./_shared":137,"./_uid":145}],137:[function(_dereq_,module,exports){ -var global = _dereq_('./_global') - , SHARED = '__core-js_shared__' - , store = global[SHARED] || (global[SHARED] = {}); -module.exports = function(key){ - return store[key] || (store[key] = {}); -}; -},{"./_global":100}],138:[function(_dereq_,module,exports){ -var toInteger = _dereq_('./_to-integer') - , defined = _dereq_('./_defined'); -// true -> String#at -// false -> String#codePointAt -module.exports = function(TO_STRING){ - return function(that, pos){ - var s = String(defined(that)) - , i = toInteger(pos) - , l = s.length - , a, b; - if(i < 0 || i >= l)return TO_STRING ? '' : undefined; - a = s.charCodeAt(i); - return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff - ? TO_STRING ? s.charAt(i) : a - : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000; - }; -}; -},{"./_defined":92,"./_to-integer":140}],139:[function(_dereq_,module,exports){ -var toInteger = _dereq_('./_to-integer') - , max = Math.max - , min = Math.min; -module.exports = function(index, length){ - index = toInteger(index); - return index < 0 ? max(index + length, 0) : min(index, length); -}; -},{"./_to-integer":140}],140:[function(_dereq_,module,exports){ -// 7.1.4 ToInteger -var ceil = Math.ceil - , floor = Math.floor; -module.exports = function(it){ - return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it); -}; -},{}],141:[function(_dereq_,module,exports){ -// to indexed object, toObject with fallback for non-array-like ES3 strings -var IObject = _dereq_('./_iobject') - , defined = _dereq_('./_defined'); -module.exports = function(it){ - return IObject(defined(it)); -}; -},{"./_defined":92,"./_iobject":105}],142:[function(_dereq_,module,exports){ -// 7.1.15 ToLength -var toInteger = _dereq_('./_to-integer') - , min = Math.min; -module.exports = function(it){ - return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 -}; -},{"./_to-integer":140}],143:[function(_dereq_,module,exports){ -// 7.1.13 ToObject(argument) -var defined = _dereq_('./_defined'); -module.exports = function(it){ - return Object(defined(it)); -}; -},{"./_defined":92}],144:[function(_dereq_,module,exports){ -// 7.1.1 ToPrimitive(input [, PreferredType]) -var isObject = _dereq_('./_is-object'); -// instead of the ES6 spec version, we didn't implement @@toPrimitive case -// and the second argument - flag - preferred type is a string -module.exports = function(it, S){ - if(!isObject(it))return it; - var fn, val; - if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val; - if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val; - if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val; - throw TypeError("Can't convert object to primitive value"); -}; -},{"./_is-object":108}],145:[function(_dereq_,module,exports){ -var id = 0 - , px = Math.random(); -module.exports = function(key){ - return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36)); -}; -},{}],146:[function(_dereq_,module,exports){ -var global = _dereq_('./_global') - , core = _dereq_('./_core') - , LIBRARY = _dereq_('./_library') - , wksExt = _dereq_('./_wks-ext') - , defineProperty = _dereq_('./_object-dp').f; -module.exports = function(name){ - var $Symbol = core.Symbol || (core.Symbol = LIBRARY ? {} : global.Symbol || {}); - if(name.charAt(0) != '_' && !(name in $Symbol))defineProperty($Symbol, name, {value: wksExt.f(name)}); -}; -},{"./_core":90,"./_global":100,"./_library":115,"./_object-dp":119,"./_wks-ext":147}],147:[function(_dereq_,module,exports){ -exports.f = _dereq_('./_wks'); -},{"./_wks":148}],148:[function(_dereq_,module,exports){ -var store = _dereq_('./_shared')('wks') - , uid = _dereq_('./_uid') - , Symbol = _dereq_('./_global').Symbol - , USE_SYMBOL = typeof Symbol == 'function'; - -var $exports = module.exports = function(name){ - return store[name] || (store[name] = - USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name)); -}; - -$exports.store = store; -},{"./_global":100,"./_shared":137,"./_uid":145}],149:[function(_dereq_,module,exports){ -var classof = _dereq_('./_classof') - , ITERATOR = _dereq_('./_wks')('iterator') - , Iterators = _dereq_('./_iterators'); -module.exports = _dereq_('./_core').getIteratorMethod = function(it){ - if(it != undefined)return it[ITERATOR] - || it['@@iterator'] - || Iterators[classof(it)]; -}; -},{"./_classof":84,"./_core":90,"./_iterators":113,"./_wks":148}],150:[function(_dereq_,module,exports){ -var anObject = _dereq_('./_an-object') - , get = _dereq_('./core.get-iterator-method'); -module.exports = _dereq_('./_core').getIterator = function(it){ - var iterFn = get(it); - if(typeof iterFn != 'function')throw TypeError(it + ' is not iterable!'); - return anObject(iterFn.call(it)); -}; -},{"./_an-object":78,"./_core":90,"./core.get-iterator-method":149}],151:[function(_dereq_,module,exports){ -'use strict'; -var addToUnscopables = _dereq_('./_add-to-unscopables') - , step = _dereq_('./_iter-step') - , Iterators = _dereq_('./_iterators') - , toIObject = _dereq_('./_to-iobject'); - -// 22.1.3.4 Array.prototype.entries() -// 22.1.3.13 Array.prototype.keys() -// 22.1.3.29 Array.prototype.values() -// 22.1.3.30 Array.prototype[@@iterator]() -module.exports = _dereq_('./_iter-define')(Array, 'Array', function(iterated, kind){ - this._t = toIObject(iterated); // target - this._i = 0; // next index - this._k = kind; // kind -// 22.1.5.2.1 %ArrayIteratorPrototype%.next() -}, function(){ - var O = this._t - , kind = this._k - , index = this._i++; - if(!O || index >= O.length){ - this._t = undefined; - return step(1); - } - if(kind == 'keys' )return step(0, index); - if(kind == 'values')return step(0, O[index]); - return step(0, [index, O[index]]); -}, 'values'); - -// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7) -Iterators.Arguments = Iterators.Array; - -addToUnscopables('keys'); -addToUnscopables('values'); -addToUnscopables('entries'); -},{"./_add-to-unscopables":76,"./_iter-define":111,"./_iter-step":112,"./_iterators":113,"./_to-iobject":141}],152:[function(_dereq_,module,exports){ -'use strict'; -var strong = _dereq_('./_collection-strong'); - -// 23.1 Map Objects -module.exports = _dereq_('./_collection')('Map', function(get){ - return function Map(){ return get(this, arguments.length > 0 ? arguments[0] : undefined); }; -}, { - // 23.1.3.6 Map.prototype.get(key) - get: function get(key){ - var entry = strong.getEntry(this, key); - return entry && entry.v; - }, - // 23.1.3.9 Map.prototype.set(key, value) - set: function set(key, value){ - return strong.def(this, key === 0 ? 0 : key, value); - } -}, strong, true); -},{"./_collection":89,"./_collection-strong":86}],153:[function(_dereq_,module,exports){ -var $export = _dereq_('./_export') -// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) -$export($export.S, 'Object', {create: _dereq_('./_object-create')}); -},{"./_export":97,"./_object-create":118}],154:[function(_dereq_,module,exports){ -var $export = _dereq_('./_export'); -// 19.1.2.4 / 15.2.3.6 Object.defineProperty(O, P, Attributes) -$export($export.S + $export.F * !_dereq_('./_descriptors'), 'Object', {defineProperty: _dereq_('./_object-dp').f}); -},{"./_descriptors":93,"./_export":97,"./_object-dp":119}],155:[function(_dereq_,module,exports){ -// 19.1.2.5 Object.freeze(O) -var isObject = _dereq_('./_is-object') - , meta = _dereq_('./_meta').onFreeze; - -_dereq_('./_object-sap')('freeze', function($freeze){ - return function freeze(it){ - return $freeze && isObject(it) ? $freeze(meta(it)) : it; - }; -}); -},{"./_is-object":108,"./_meta":116,"./_object-sap":129}],156:[function(_dereq_,module,exports){ -// 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) -var toIObject = _dereq_('./_to-iobject') - , $getOwnPropertyDescriptor = _dereq_('./_object-gopd').f; - -_dereq_('./_object-sap')('getOwnPropertyDescriptor', function(){ - return function getOwnPropertyDescriptor(it, key){ - return $getOwnPropertyDescriptor(toIObject(it), key); - }; -}); -},{"./_object-gopd":121,"./_object-sap":129,"./_to-iobject":141}],157:[function(_dereq_,module,exports){ -// 19.1.2.9 Object.getPrototypeOf(O) -var toObject = _dereq_('./_to-object') - , $getPrototypeOf = _dereq_('./_object-gpo'); - -_dereq_('./_object-sap')('getPrototypeOf', function(){ - return function getPrototypeOf(it){ - return $getPrototypeOf(toObject(it)); - }; -}); -},{"./_object-gpo":125,"./_object-sap":129,"./_to-object":143}],158:[function(_dereq_,module,exports){ -// 19.1.2.14 Object.keys(O) -var toObject = _dereq_('./_to-object') - , $keys = _dereq_('./_object-keys'); - -_dereq_('./_object-sap')('keys', function(){ - return function keys(it){ - return $keys(toObject(it)); - }; -}); -},{"./_object-keys":127,"./_object-sap":129,"./_to-object":143}],159:[function(_dereq_,module,exports){ -// 19.1.3.19 Object.setPrototypeOf(O, proto) -var $export = _dereq_('./_export'); -$export($export.S, 'Object', {setPrototypeOf: _dereq_('./_set-proto').set}); -},{"./_export":97,"./_set-proto":133}],160:[function(_dereq_,module,exports){ - -},{}],161:[function(_dereq_,module,exports){ -'use strict'; -var $at = _dereq_('./_string-at')(true); - -// 21.1.3.27 String.prototype[@@iterator]() -_dereq_('./_iter-define')(String, 'String', function(iterated){ - this._t = String(iterated); // target - this._i = 0; // next index -// 21.1.5.2.1 %StringIteratorPrototype%.next() -}, function(){ - var O = this._t - , index = this._i - , point; - if(index >= O.length)return {value: undefined, done: true}; - point = $at(O, index); - this._i += point.length; - return {value: point, done: false}; -}); -},{"./_iter-define":111,"./_string-at":138}],162:[function(_dereq_,module,exports){ -'use strict'; -// ECMAScript 6 symbols shim -var global = _dereq_('./_global') - , has = _dereq_('./_has') - , DESCRIPTORS = _dereq_('./_descriptors') - , $export = _dereq_('./_export') - , redefine = _dereq_('./_redefine') - , META = _dereq_('./_meta').KEY - , $fails = _dereq_('./_fails') - , shared = _dereq_('./_shared') - , setToStringTag = _dereq_('./_set-to-string-tag') - , uid = _dereq_('./_uid') - , wks = _dereq_('./_wks') - , wksExt = _dereq_('./_wks-ext') - , wksDefine = _dereq_('./_wks-define') - , keyOf = _dereq_('./_keyof') - , enumKeys = _dereq_('./_enum-keys') - , isArray = _dereq_('./_is-array') - , anObject = _dereq_('./_an-object') - , toIObject = _dereq_('./_to-iobject') - , toPrimitive = _dereq_('./_to-primitive') - , createDesc = _dereq_('./_property-desc') - , _create = _dereq_('./_object-create') - , gOPNExt = _dereq_('./_object-gopn-ext') - , $GOPD = _dereq_('./_object-gopd') - , $DP = _dereq_('./_object-dp') - , $keys = _dereq_('./_object-keys') - , gOPD = $GOPD.f - , dP = $DP.f - , gOPN = gOPNExt.f - , $Symbol = global.Symbol - , $JSON = global.JSON - , _stringify = $JSON && $JSON.stringify - , PROTOTYPE = 'prototype' - , HIDDEN = wks('_hidden') - , TO_PRIMITIVE = wks('toPrimitive') - , isEnum = {}.propertyIsEnumerable - , SymbolRegistry = shared('symbol-registry') - , AllSymbols = shared('symbols') - , OPSymbols = shared('op-symbols') - , ObjectProto = Object[PROTOTYPE] - , USE_NATIVE = typeof $Symbol == 'function' - , QObject = global.QObject; -// Don't use setters in Qt Script, https://github.com/zloirock/core-js/issues/173 -var setter = !QObject || !QObject[PROTOTYPE] || !QObject[PROTOTYPE].findChild; - -// fallback for old Android, https://code.google.com/p/v8/issues/detail?id=687 -var setSymbolDesc = DESCRIPTORS && $fails(function(){ - return _create(dP({}, 'a', { - get: function(){ return dP(this, 'a', {value: 7}).a; } - })).a != 7; -}) ? function(it, key, D){ - var protoDesc = gOPD(ObjectProto, key); - if(protoDesc)delete ObjectProto[key]; - dP(it, key, D); - if(protoDesc && it !== ObjectProto)dP(ObjectProto, key, protoDesc); -} : dP; - -var wrap = function(tag){ - var sym = AllSymbols[tag] = _create($Symbol[PROTOTYPE]); - sym._k = tag; - return sym; -}; - -var isSymbol = USE_NATIVE && typeof $Symbol.iterator == 'symbol' ? function(it){ - return typeof it == 'symbol'; -} : function(it){ - return it instanceof $Symbol; -}; - -var $defineProperty = function defineProperty(it, key, D){ - if(it === ObjectProto)$defineProperty(OPSymbols, key, D); - anObject(it); - key = toPrimitive(key, true); - anObject(D); - if(has(AllSymbols, key)){ - if(!D.enumerable){ - if(!has(it, HIDDEN))dP(it, HIDDEN, createDesc(1, {})); - it[HIDDEN][key] = true; - } else { - if(has(it, HIDDEN) && it[HIDDEN][key])it[HIDDEN][key] = false; - D = _create(D, {enumerable: createDesc(0, false)}); - } return setSymbolDesc(it, key, D); - } return dP(it, key, D); -}; -var $defineProperties = function defineProperties(it, P){ - anObject(it); - var keys = enumKeys(P = toIObject(P)) - , i = 0 - , l = keys.length - , key; - while(l > i)$defineProperty(it, key = keys[i++], P[key]); - return it; -}; -var $create = function create(it, P){ - return P === undefined ? _create(it) : $defineProperties(_create(it), P); -}; -var $propertyIsEnumerable = function propertyIsEnumerable(key){ - var E = isEnum.call(this, key = toPrimitive(key, true)); - if(this === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return false; - return E || !has(this, key) || !has(AllSymbols, key) || has(this, HIDDEN) && this[HIDDEN][key] ? E : true; -}; -var $getOwnPropertyDescriptor = function getOwnPropertyDescriptor(it, key){ - it = toIObject(it); - key = toPrimitive(key, true); - if(it === ObjectProto && has(AllSymbols, key) && !has(OPSymbols, key))return; - var D = gOPD(it, key); - if(D && has(AllSymbols, key) && !(has(it, HIDDEN) && it[HIDDEN][key]))D.enumerable = true; - return D; -}; -var $getOwnPropertyNames = function getOwnPropertyNames(it){ - var names = gOPN(toIObject(it)) - , result = [] - , i = 0 - , key; - while(names.length > i){ - if(!has(AllSymbols, key = names[i++]) && key != HIDDEN && key != META)result.push(key); - } return result; -}; -var $getOwnPropertySymbols = function getOwnPropertySymbols(it){ - var IS_OP = it === ObjectProto - , names = gOPN(IS_OP ? OPSymbols : toIObject(it)) - , result = [] - , i = 0 - , key; - while(names.length > i){ - if(has(AllSymbols, key = names[i++]) && (IS_OP ? has(ObjectProto, key) : true))result.push(AllSymbols[key]); - } return result; -}; - -// 19.4.1.1 Symbol([description]) -if(!USE_NATIVE){ - $Symbol = function Symbol(){ - if(this instanceof $Symbol)throw TypeError('Symbol is not a constructor!'); - var tag = uid(arguments.length > 0 ? arguments[0] : undefined); - var $set = function(value){ - if(this === ObjectProto)$set.call(OPSymbols, value); - if(has(this, HIDDEN) && has(this[HIDDEN], tag))this[HIDDEN][tag] = false; - setSymbolDesc(this, tag, createDesc(1, value)); - }; - if(DESCRIPTORS && setter)setSymbolDesc(ObjectProto, tag, {configurable: true, set: $set}); - return wrap(tag); - }; - redefine($Symbol[PROTOTYPE], 'toString', function toString(){ - return this._k; - }); - - $GOPD.f = $getOwnPropertyDescriptor; - $DP.f = $defineProperty; - _dereq_('./_object-gopn').f = gOPNExt.f = $getOwnPropertyNames; - _dereq_('./_object-pie').f = $propertyIsEnumerable; - _dereq_('./_object-gops').f = $getOwnPropertySymbols; - - if(DESCRIPTORS && !_dereq_('./_library')){ - redefine(ObjectProto, 'propertyIsEnumerable', $propertyIsEnumerable, true); - } - - wksExt.f = function(name){ - return wrap(wks(name)); - } -} - -$export($export.G + $export.W + $export.F * !USE_NATIVE, {Symbol: $Symbol}); - -for(var symbols = ( - // 19.4.2.2, 19.4.2.3, 19.4.2.4, 19.4.2.6, 19.4.2.8, 19.4.2.9, 19.4.2.10, 19.4.2.11, 19.4.2.12, 19.4.2.13, 19.4.2.14 - 'hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables' -).split(','), i = 0; symbols.length > i; )wks(symbols[i++]); - -for(var symbols = $keys(wks.store), i = 0; symbols.length > i; )wksDefine(symbols[i++]); - -$export($export.S + $export.F * !USE_NATIVE, 'Symbol', { - // 19.4.2.1 Symbol.for(key) - 'for': function(key){ - return has(SymbolRegistry, key += '') - ? SymbolRegistry[key] - : SymbolRegistry[key] = $Symbol(key); - }, - // 19.4.2.5 Symbol.keyFor(sym) - keyFor: function keyFor(key){ - if(isSymbol(key))return keyOf(SymbolRegistry, key); - throw TypeError(key + ' is not a symbol!'); - }, - useSetter: function(){ setter = true; }, - useSimple: function(){ setter = false; } -}); - -$export($export.S + $export.F * !USE_NATIVE, 'Object', { - // 19.1.2.2 Object.create(O [, Properties]) - create: $create, - // 19.1.2.4 Object.defineProperty(O, P, Attributes) - defineProperty: $defineProperty, - // 19.1.2.3 Object.defineProperties(O, Properties) - defineProperties: $defineProperties, - // 19.1.2.6 Object.getOwnPropertyDescriptor(O, P) - getOwnPropertyDescriptor: $getOwnPropertyDescriptor, - // 19.1.2.7 Object.getOwnPropertyNames(O) - getOwnPropertyNames: $getOwnPropertyNames, - // 19.1.2.8 Object.getOwnPropertySymbols(O) - getOwnPropertySymbols: $getOwnPropertySymbols -}); - -// 24.3.2 JSON.stringify(value [, replacer [, space]]) -$JSON && $export($export.S + $export.F * (!USE_NATIVE || $fails(function(){ - var S = $Symbol(); - // MS Edge converts symbol values to JSON as {} - // WebKit converts symbol values to JSON as null - // V8 throws on boxed symbols - return _stringify([S]) != '[null]' || _stringify({a: S}) != '{}' || _stringify(Object(S)) != '{}'; -})), 'JSON', { - stringify: function stringify(it){ - if(it === undefined || isSymbol(it))return; // IE8 returns string on undefined - var args = [it] - , i = 1 - , replacer, $replacer; - while(arguments.length > i)args.push(arguments[i++]); - replacer = args[1]; - if(typeof replacer == 'function')$replacer = replacer; - if($replacer || !isArray(replacer))replacer = function(key, value){ - if($replacer)value = $replacer.call(this, key, value); - if(!isSymbol(value))return value; - }; - args[1] = replacer; - return _stringify.apply($JSON, args); - } -}); - -// 19.4.3.4 Symbol.prototype[@@toPrimitive](hint) -$Symbol[PROTOTYPE][TO_PRIMITIVE] || _dereq_('./_hide')($Symbol[PROTOTYPE], TO_PRIMITIVE, $Symbol[PROTOTYPE].valueOf); -// 19.4.3.5 Symbol.prototype[@@toStringTag] -setToStringTag($Symbol, 'Symbol'); -// 20.2.1.9 Math[@@toStringTag] -setToStringTag(Math, 'Math', true); -// 24.3.3 JSON[@@toStringTag] -setToStringTag(global.JSON, 'JSON', true); -},{"./_an-object":78,"./_descriptors":93,"./_enum-keys":96,"./_export":97,"./_fails":98,"./_global":100,"./_has":101,"./_hide":102,"./_is-array":107,"./_keyof":114,"./_library":115,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_object-gopd":121,"./_object-gopn":123,"./_object-gopn-ext":122,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_property-desc":130,"./_redefine":132,"./_set-to-string-tag":135,"./_shared":137,"./_to-iobject":141,"./_to-primitive":144,"./_uid":145,"./_wks":148,"./_wks-define":146,"./_wks-ext":147}],163:[function(_dereq_,module,exports){ -'use strict'; -var each = _dereq_('./_array-methods')(0) - , redefine = _dereq_('./_redefine') - , meta = _dereq_('./_meta') - , assign = _dereq_('./_object-assign') - , weak = _dereq_('./_collection-weak') - , isObject = _dereq_('./_is-object') - , getWeak = meta.getWeak - , isExtensible = Object.isExtensible - , uncaughtFrozenStore = weak.ufstore - , tmp = {} - , InternalMap; - -var wrapper = function(get){ - return function WeakMap(){ - return get(this, arguments.length > 0 ? arguments[0] : undefined); - }; -}; - -var methods = { - // 23.3.3.3 WeakMap.prototype.get(key) - get: function get(key){ - if(isObject(key)){ - var data = getWeak(key); - if(data === true)return uncaughtFrozenStore(this).get(key); - return data ? data[this._i] : undefined; - } - }, - // 23.3.3.5 WeakMap.prototype.set(key, value) - set: function set(key, value){ - return weak.def(this, key, value); - } -}; - -// 23.3 WeakMap Objects -var $WeakMap = module.exports = _dereq_('./_collection')('WeakMap', wrapper, methods, weak, true, true); - -// IE11 WeakMap frozen keys fix -if(new $WeakMap().set((Object.freeze || Object)(tmp), 7).get(tmp) != 7){ - InternalMap = weak.getConstructor(wrapper); - assign(InternalMap.prototype, methods); - meta.NEED = true; - each(['delete', 'has', 'get', 'set'], function(key){ - var proto = $WeakMap.prototype - , method = proto[key]; - redefine(proto, key, function(a, b){ - // store frozen objects on internal weakmap shim - if(isObject(a) && !isExtensible(a)){ - if(!this._f)this._f = new InternalMap; - var result = this._f[key](a, b); - return key == 'set' ? this : result; - // store all the rest on native weakmap - } return method.call(this, a, b); - }); - }); -} -},{"./_array-methods":81,"./_collection":89,"./_collection-weak":88,"./_is-object":108,"./_meta":116,"./_object-assign":117,"./_redefine":132}],164:[function(_dereq_,module,exports){ -// https://github.com/DavidBruant/Map-Set.prototype.toJSON -var $export = _dereq_('./_export'); - -$export($export.P + $export.R, 'Map', {toJSON: _dereq_('./_collection-to-json')('Map')}); -},{"./_collection-to-json":87,"./_export":97}],165:[function(_dereq_,module,exports){ -_dereq_('./_wks-define')('asyncIterator'); -},{"./_wks-define":146}],166:[function(_dereq_,module,exports){ -_dereq_('./_wks-define')('observable'); -},{"./_wks-define":146}],167:[function(_dereq_,module,exports){ -_dereq_('./es6.array.iterator'); -var global = _dereq_('./_global') - , hide = _dereq_('./_hide') - , Iterators = _dereq_('./_iterators') - , TO_STRING_TAG = _dereq_('./_wks')('toStringTag'); - -for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){ - var NAME = collections[i] - , Collection = global[NAME] - , proto = Collection && Collection.prototype; - if(proto && !proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME); - Iterators[NAME] = Iterators.Array; -} -},{"./_global":100,"./_hide":102,"./_iterators":113,"./_wks":148,"./es6.array.iterator":151}],168:[function(_dereq_,module,exports){ -arguments[4][160][0].apply(exports,arguments) -},{"dup":160}],169:[function(_dereq_,module,exports){ -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. - -function EventEmitter() { - this._events = this._events || {}; - this._maxListeners = this._maxListeners || undefined; -} -module.exports = EventEmitter; - -// Backwards-compat with node 0.10.x -EventEmitter.EventEmitter = EventEmitter; - -EventEmitter.prototype._events = undefined; -EventEmitter.prototype._maxListeners = undefined; - -// By default EventEmitters will print a warning if more than 10 listeners are -// added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; - -// Obviously not all Emitters should be limited to 10. This function allows -// that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); - this._maxListeners = n; - return this; -}; - -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; - - if (!this._events) - this._events = {}; - - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } - } - - handler = this._events[type]; - - if (isUndefined(handler)) - return false; - - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - handler.apply(this, args); - } - } else if (isObject(handler)) { - len = arguments.length; - args = new Array(len - 1); - for (i = 1; i < len; i++) - args[i - 1] = arguments[i]; - - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); - } - - return true; -}; - -EventEmitter.prototype.addListener = function(type, listener) { - var m; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events) - this._events = {}; - - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); - - if (!this._events[type]) - // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - var m; - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; - } else { - m = EventEmitter.defaultMaxListeners; - } - - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); - } - } - } - - return this; -}; - -EventEmitter.prototype.on = EventEmitter.prototype.addListener; - -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); - } - } - - g.listener = listener; - this.on(type, g); - - return this; -}; - -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) - return this; - - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } - - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } - - return this; -}; - -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.listenerCount = function(emitter, type) { - var ret; - if (!emitter._events || !emitter._events[type]) - ret = 0; - else if (isFunction(emitter._events[type])) - ret = 1; - else - ret = emitter._events[type].length; - return ret; -}; - -function isFunction(arg) { - return typeof arg === 'function'; -} - -function isNumber(arg) { - return typeof arg === 'number'; -} - -function isObject(arg) { - return typeof arg === 'object' && arg !== null; -} - -function isUndefined(arg) { - return arg === void 0; -} - -},{}]},{},[10])(10) -}); \ No newline at end of file diff --git a/dist/parse.min.js b/dist/parse.min.js deleted file mode 100644 index 1e917b729..000000000 --- a/dist/parse.min.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Parse JavaScript SDK v1.9.2 - * - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * The source tree of this library can be found at - * https://github.com/ParsePlatform/Parse-SDK-JS - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ -!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var t;t="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,t.Parse=e()}}(function(){return function e(t,r,n){function o(i,s){if(!r[i]){if(!t[i]){var u="function"==typeof require&&require;if(!s&&u)return u(i,!0);if(a)return a(i,!0);var l=new Error("Cannot find module '"+i+"'");throw l.code="MODULE_NOT_FOUND",l}var c=r[i]={exports:{}};t[i][0].call(c.exports,function(e){var r=t[i][1][e];return o(r?r:e)},c,c.exports,e,t,r,n)}return r[i].exports}for(var a="function"==typeof require&&require,i=0;i>2&63),o(n<<4&48|a>>4&15),s?o(a<<2&60|i>>6&3):"=",u?o(63&i):"="].join("")}return t.join("")}}]),e}();r["default"]=h;var p={saveFile:function(e,t){if("file"!==t.format)throw new Error("saveFile can only be used with File-type sources.");var r={"X-Parse-Application-ID":c["default"].get("APPLICATION_ID"),"X-Parse-JavaScript-Key":c["default"].get("JAVASCRIPT_KEY"),"Content-Type":t.type||(t.file?t.file.type:null)},n=c["default"].get("SERVER_URL");return"/"!==n[n.length-1]&&(n+="/"),n+="files/"+e,c["default"].getRESTController().ajax("POST",n,t.file,r)},saveBase64:function(e,t){if("base64"!==t.format)throw new Error("saveBase64 can only be used with Base64-type sources.");var r={base64:t.base64};return t.type&&(r._ContentType=t.type),c["default"].getRESTController().request("POST","files/"+e,r)}};c["default"].setFileController(p)},{"./CoreManager":3,"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57}],15:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var o=e("babel-runtime/helpers/typeof"),a=n(o),i=e("babel-runtime/helpers/classCallCheck"),s=n(i),u=e("babel-runtime/helpers/createClass"),l=n(u),c=e("./ParsePromise"),f=n(c),d=function(){function e(t,r){(0,s["default"])(this,e),Array.isArray(t)?(e._validate(t[0],t[1]),this._latitude=t[0],this._longitude=t[1]):"object"===("undefined"==typeof t?"undefined":(0,a["default"])(t))?(e._validate(t.latitude,t.longitude),this._latitude=t.latitude,this._longitude=t.longitude):"number"==typeof t&&"number"==typeof r?(e._validate(t,r),this._latitude=t,this._longitude=r):(this._latitude=0,this._longitude=0)}return(0,l["default"])(e,[{key:"toJSON",value:function(){return e._validate(this._latitude,this._longitude),{__type:"GeoPoint",latitude:this._latitude,longitude:this._longitude}}},{key:"equals",value:function(t){return t instanceof e&&this.latitude===t.latitude&&this.longitude===t.longitude}},{key:"radiansTo",value:function(e){var t=Math.PI/180,r=this.latitude*t,n=this.longitude*t,o=e.latitude*t,a=e.longitude*t,i=Math.sin((r-o)/2),s=Math.sin((n-a)/2),u=i*i+Math.cos(r)*Math.cos(o)*s*s;return u=Math.min(1,u),2*Math.asin(Math.sqrt(u))}},{key:"kilometersTo",value:function(e){return 6371*this.radiansTo(e)}},{key:"milesTo",value:function(e){return 3958.8*this.radiansTo(e)}},{key:"latitude",get:function(){return this._latitude},set:function(t){e._validate(t,this.longitude),this._latitude=t}},{key:"longitude",get:function(){return this._longitude},set:function(t){e._validate(this.latitude,t),this._longitude=t}}],[{key:"_validate",value:function(e,t){if(e!==e||t!==t)throw new TypeError("GeoPoint latitude and longitude must be valid numbers");if(e<-90)throw new TypeError("GeoPoint latitude out of bounds: "+e+" < -90.0.");if(e>90)throw new TypeError("GeoPoint latitude out of bounds: "+e+" > 90.0.");if(t<-180)throw new TypeError("GeoPoint longitude out of bounds: "+t+" < -180.0.");if(t>180)throw new TypeError("GeoPoint longitude out of bounds: "+t+" > 180.0.")}},{key:"current",value:function(t){var r=new f["default"];return navigator.geolocation.getCurrentPosition(function(t){r.resolve(new e(t.coords.latitude,t.coords.longitude))},function(e){r.reject(e)}),r._thenRunCallbacks(t)}}]),e}();r["default"]=d},{"./ParsePromise":20,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],16:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var o=e("babel-runtime/helpers/typeof"),a=n(o),i=e("babel-runtime/core-js/object/get-prototype-of"),s=n(i),u=e("babel-runtime/helpers/classCallCheck"),l=n(u),c=e("babel-runtime/helpers/possibleConstructorReturn"),f=n(c),d=e("babel-runtime/helpers/inherits"),h=n(d),p=e("./ParseObject"),_=n(p),v=function(e){function t(e){(0,l["default"])(this,t);var r=(0,f["default"])(this,(t.__proto__||(0,s["default"])(t)).call(this,"_Installation"));if(e&&"object"===("undefined"==typeof e?"undefined":(0,a["default"])(e))&&!r.set(e||{}))throw new Error("Can't create an invalid Session");return r}return(0,h["default"])(t,e),t}(_["default"]);r["default"]=v,_["default"].registerSubclass("_Installation",v)},{"./ParseObject":18,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60,"babel-runtime/helpers/typeof":61}],17:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(){var e=h["default"].getLiveQueryController();e.open()}function a(){var e=h["default"].getLiveQueryController();e.close()}function i(){var e=h["default"].getUserController();return e.currentUserAsync().then(function(e){return e?e.getSessionToken():void 0})}function s(){return h["default"].getLiveQueryController().getDefaultLiveQueryClient()}Object.defineProperty(r,"__esModule",{value:!0});var u=e("./EventEmitter"),l=n(u),c=e("./LiveQueryClient"),f=n(c),d=e("./CoreManager"),h=n(d),p=e("./ParsePromise"),_=n(p),v=new l["default"];v.open=o,v.close=a,v.on("error",function(){}),r["default"]=v;var y=void 0,b={setDefaultLiveQueryClient:function(e){y=e},getDefaultLiveQueryClient:function(){return y?_["default"].as(y):i().then(function(e){var t=h["default"].get("LIVEQUERY_SERVER_URL");if(t&&0!==t.indexOf("ws"))throw new Error("You need to set a proper Parse LiveQuery server url before using LiveQueryClient");if(!t){var r=h["default"].get("SERVER_URL"),n="ws://";0===r.indexOf("https")&&(n="wss://");var o=r.replace(/^https?:\/\//,"");t=n+o,h["default"].set("LIVEQUERY_SERVER_URL",t)}var a=h["default"].get("APPLICATION_ID"),i=h["default"].get("JAVASCRIPT_KEY"),s=h["default"].get("MASTER_KEY");return y=new f["default"]({applicationId:a,serverURL:t,javascriptKey:i,masterKey:s,sessionToken:e}),y.on("error",function(e){v.emit("error",e)}),y.on("open",function(){v.emit("open")}),y.on("close",function(){v.emit("close")}),y})},open:function(){var e=this;s().then(function(t){e.resolve(t.open())})},close:function(){var e=this;s().then(function(t){e.resolve(t.close())})},subscribe:function(e){var t=this,r=new l["default"];return s().then(function(n){n.shouldOpen()&&n.open();var o=i();return o.then(function(o){var a=n.subscribe(e,o);r.id=a.id,r.query=a.query,r.sessionToken=a.sessionToken,r.unsubscribe=a.unsubscribe,a.on("open",function(){r.emit("open")}),a.on("create",function(e){r.emit("create",e)}),a.on("update",function(e){r.emit("update",e)}),a.on("enter",function(e){r.emit("enter",e)}),a.on("leave",function(e){r.emit("leave",e)}),a.on("delete",function(e){r.emit("delete",e)}),t.resolve()})}),r},unsubscribe:function(e){var t=this;s().then(function(r){t.resolve(r.unsubscribe(e))})},_clearCachedDefaultClient:function(){y=null}};h["default"].setLiveQueryController(b)},{"./CoreManager":3,"./EventEmitter":4,"./LiveQueryClient":7,"./ParsePromise":20}],18:[function(e,t,r){"use strict";function n(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r]);return t["default"]=e,t}function o(e){return e&&e.__esModule?e:{"default":e}}function a(){var e=k["default"].get("SERVER_URL");"/"!==e[e.length-1]&&(e+="/");var t=e.replace(/https?:\/\//,"");return t.substr(t.indexOf("/"))}Object.defineProperty(r,"__esModule",{value:!0});var i=e("babel-runtime/core-js/object/define-property"),s=o(i),u=e("babel-runtime/core-js/object/create"),l=o(u),c=e("babel-runtime/core-js/object/freeze"),f=o(c),d=e("babel-runtime/core-js/json/stringify"),h=o(d),p=e("babel-runtime/core-js/object/keys"),_=o(p),v=e("babel-runtime/helpers/typeof"),y=o(v),b=e("babel-runtime/helpers/classCallCheck"),g=o(b),m=e("babel-runtime/helpers/createClass"),C=o(m),j=e("./CoreManager"),k=o(j),O=e("./canBeSerialized"),w=o(O),S=e("./decode"),E=o(S),P=e("./encode"),A=o(P),I=e("./equals"),T=(o(I),e("./escape")),N=o(T),R=e("./ParseACL"),M=o(R),x=e("./parseDate"),D=o(x),L=e("./ParseError"),U=o(L),F=e("./ParseFile"),K=o(F),q=e("./ParseOp"),J=e("./ParsePromise"),W=o(J),Q=e("./ParseQuery"),B=o(Q),V=e("./ParseRelation"),G=o(V),z=e("./SingleInstanceStateController"),Y=n(z),H=e("./unique"),$=o(H),X=e("./UniqueInstanceStateController"),Z=n(X),ee=e("./unsavedChildren"),te=o(ee),re={},ne=0,oe=0,ae=!k["default"].get("IS_NODE");ae?k["default"].setObjectStateController(Y):k["default"].setObjectStateController(Z);var ie=function(){function e(t,r,n){(0,g["default"])(this,e),"function"==typeof this.initialize&&this.initialize.apply(this,arguments);var o=null;if(this._objCount=oe++,"string"==typeof t)this.className=t,r&&"object"===("undefined"==typeof r?"undefined":(0,y["default"])(r))&&(o=r);else if(t&&"object"===("undefined"==typeof t?"undefined":(0,y["default"])(t))){this.className=t.className,o={};for(var a in t)"className"!==a&&(o[a]=t[a]);r&&"object"===("undefined"==typeof r?"undefined":(0,y["default"])(r))&&(n=r)}if(o&&!this.set(o,n))throw new Error("Can't create an invalid Parse Object")}return(0,C["default"])(e,[{key:"_getId",value:function(){if("string"==typeof this.id)return this.id;if("string"==typeof this._localId)return this._localId;var e="local"+String(ne++);return this._localId=e,e}},{key:"_getStateIdentifier",value:function(){if(ae){var e=this.id;return e||(e=this._getId()),{id:e,className:this.className}}return this}},{key:"_getServerData",value:function(){var e=k["default"].getObjectStateController();return e.getServerData(this._getStateIdentifier())}},{key:"_clearServerData",value:function(){var e=this._getServerData(),t={};for(var r in e)t[r]=void 0;var n=k["default"].getObjectStateController();n.setServerData(this._getStateIdentifier(),t)}},{key:"_getPendingOps",value:function(){var e=k["default"].getObjectStateController();return e.getPendingOps(this._getStateIdentifier())}},{key:"_clearPendingOps",value:function(){var e=this._getPendingOps(),t=e[e.length-1],r=(0,_["default"])(t);r.forEach(function(e){delete t[e]})}},{key:"_getDirtyObjectAttributes",value:function(){var t=this.attributes,r=k["default"].getObjectStateController(),n=r.getObjectCache(this._getStateIdentifier()),o={};for(var a in t){var i=t[a];if(i&&"object"===("undefined"==typeof i?"undefined":(0,y["default"])(i))&&!(i instanceof e)&&!(i instanceof K["default"])&&!(i instanceof G["default"]))try{var s=(0,A["default"])(i,!1,!0),u=(0,h["default"])(s);n[a]!==u&&(o[a]=i)}catch(l){o[a]=i}}return o}},{key:"_toFullJSON",value:function(e){var t=this.toJSON(e);return t.__type="Object",t.className=this.className,t}},{key:"_getSaveJSON",value:function(){var e=this._getPendingOps(),t=this._getDirtyObjectAttributes(),r={};for(var n in t)r[n]=new q.SetOp(t[n]).toJSON();for(n in e[0])r[n]=e[0][n].toJSON();return r}},{key:"_getSaveParams",value:function(){var e=this.id?"PUT":"POST",t=this._getSaveJSON(),r="classes/"+this.className;return this.id?r+="/"+this.id:"_User"===this.className&&(r="users"),{method:e,body:t,path:r}}},{key:"_finishFetch",value:function(e){!this.id&&e.objectId&&(this.id=e.objectId);var t=k["default"].getObjectStateController();t.initializeState(this._getStateIdentifier());var r={};for(var n in e)"ACL"===n?r[n]=new M["default"](e[n]):"objectId"!==n&&(r[n]=(0,E["default"])(e[n]),r[n]instanceof G["default"]&&r[n]._ensureParentAndKey(this,n));r.createdAt&&"string"==typeof r.createdAt&&(r.createdAt=(0,D["default"])(r.createdAt)),r.updatedAt&&"string"==typeof r.updatedAt&&(r.updatedAt=(0,D["default"])(r.updatedAt)),!r.updatedAt&&r.createdAt&&(r.updatedAt=r.createdAt),t.commitServerChanges(this._getStateIdentifier(),r)}},{key:"_setExisted",value:function(e){var t=k["default"].getObjectStateController(),r=t.getState(this._getStateIdentifier());r&&(r.existed=e)}},{key:"_migrateId",value:function(e){if(this._localId&&e)if(ae){var t=k["default"].getObjectStateController(),r=t.removeState(this._getStateIdentifier());this.id=e,delete this._localId,r&&t.initializeState(this._getStateIdentifier(),r)}else this.id=e,delete this._localId}},{key:"_handleSaveResponse",value:function(e,t){var r={},n=k["default"].getObjectStateController(),o=n.popPendingState(this._getStateIdentifier());for(var a in o)o[a]instanceof q.RelationOp?r[a]=o[a].applyTo(void 0,this,a):a in e||(r[a]=o[a].applyTo(void 0));for(a in e)"createdAt"!==a&&"updatedAt"!==a||"string"!=typeof e[a]?"ACL"===a?r[a]=new M["default"](e[a]):"objectId"!==a&&(r[a]=(0,E["default"])(e[a]),r[a]instanceof q.UnsetOp&&(r[a]=void 0)):r[a]=(0,D["default"])(e[a]);r.createdAt&&!r.updatedAt&&(r.updatedAt=r.createdAt),this._migrateId(e.objectId),201!==t&&this._setExisted(!0),n.commitServerChanges(this._getStateIdentifier(),r)}},{key:"_handleSaveError",value:function(){this._getPendingOps();var e=k["default"].getObjectStateController();e.mergeFirstPendingState(this._getStateIdentifier())}},{key:"initialize",value:function(){}},{key:"toJSON",value:function(e){var t=this.id?this.className+":"+this.id:this,e=e||[t],r={},n=this.attributes;for(var o in n)"createdAt"!==o&&"updatedAt"!==o||!n[o].toJSON?r[o]=(0,A["default"])(n[o],!1,!1,e):r[o]=n[o].toJSON();var a=this._getPendingOps();for(var o in a[0])r[o]=a[0][o].toJSON();return this.id&&(r.objectId=this.id),r}},{key:"equals",value:function(t){return this===t||t instanceof e&&this.className===t.className&&this.id===t.id&&"undefined"!=typeof this.id}},{key:"dirty",value:function(e){if(!this.id)return!0;var t=this._getPendingOps(),r=this._getDirtyObjectAttributes();if(e){if(r.hasOwnProperty(e))return!0;for(var n=0;n-1)throw new Error("Cannot modify readonly attribute: "+i);r.unset?o[i]=new q.UnsetOp:n[i]instanceof q.Op?o[i]=n[i]:n[i]&&"object"===(0,y["default"])(n[i])&&"string"==typeof n[i].__op?o[i]=(0,q.opFromJSON)(n[i]):"objectId"===i||"id"===i?"string"==typeof n[i]&&(this.id=n[i]):"ACL"!==i||"object"!==(0,y["default"])(n[i])||n[i]instanceof M["default"]?o[i]=new q.SetOp(n[i]):o[i]=new q.SetOp(new M["default"](n[i]))}var s=this.attributes,u={};for(var l in o)o[l]instanceof q.RelationOp?u[l]=o[l].applyTo(s[l],this,l):o[l]instanceof q.UnsetOp||(u[l]=o[l].applyTo(s[l]));if(!r.ignoreValidation){var c=this.validate(u);if(c)return"function"==typeof r.error&&r.error(this,c),!1}var f=this._getPendingOps(),d=f.length-1,h=k["default"].getObjectStateController();for(var l in o){var p=o[l].mergeWith(f[d][l]);h.setPendingOp(this._getStateIdentifier(),l,p)}return this}},{key:"unset",value:function(e,t){return t=t||{},t.unset=!0,this.set(e,null,t)}},{key:"increment",value:function(e,t){if("undefined"==typeof t&&(t=1),"number"!=typeof t)throw new Error("Cannot increment by a non-numeric amount.");return this.set(e,new q.IncrementOp(t))}},{key:"add",value:function(e,t){return this.set(e,new q.AddOp([t]))}},{key:"addUnique",value:function(e,t){return this.set(e,new q.AddUniqueOp([t]))}},{key:"remove",value:function(e,t){return this.set(e,new q.RemoveOp([t]))}},{key:"op",value:function(e){for(var t=this._getPendingOps(),r=t.length;r--;)if(t[r][e])return t[r][e]}},{key:"clone",value:function(){var e=new this.constructor;e.className||(e.className=this.className);var t=this.attributes;if("function"==typeof this.constructor.readOnlyAttributes){var r=this.constructor.readOnlyAttributes()||[],n={};for(var o in t)r.indexOf(o)<0&&(n[o]=t[o]);t=n}return e.set&&e.set(t),e}},{key:"newInstance",value:function(){var e=new this.constructor;if(e.className||(e.className=this.className),e.id=this.id,ae)return e;var t=k["default"].getObjectStateController();return t&&t.duplicateState(this._getStateIdentifier(),e._getStateIdentifier()),e}},{key:"isNew",value:function(){return!this.id}},{key:"existed",value:function(){if(!this.id)return!1;var e=k["default"].getObjectStateController(),t=e.getState(this._getStateIdentifier());return!!t&&t.existed}},{key:"isValid",value:function(){return!this.validate(this.attributes)}},{key:"validate",value:function(e){if(e.hasOwnProperty("ACL")&&!(e.ACL instanceof M["default"]))return new U["default"](U["default"].OTHER_CAUSE,"ACL must be a Parse ACL.");for(var t in e)if(!/^[A-Za-z][0-9A-Za-z_]*$/.test(t))return new U["default"](U["default"].INVALID_KEY_NAME);return!1}},{key:"getACL",value:function(){var e=this.get("ACL");return e instanceof M["default"]?e:null}},{key:"setACL",value:function(e,t){return this.set("ACL",e,t)}},{key:"revert",value:function(){this._clearPendingOps()}},{key:"clear",value:function(){var e=this.attributes,t={},r=["createdAt","updatedAt"];"function"==typeof this.constructor.readOnlyAttributes&&(r=r.concat(this.constructor.readOnlyAttributes()));for(var n in e)r.indexOf(n)<0&&(t[n]=!0);return this.set(t,{unset:!0})}},{key:"fetch",value:function(e){e=e||{};var t={};e.hasOwnProperty("useMasterKey")&&(t.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(t.sessionToken=e.sessionToken);var r=k["default"].getObjectController();return r.fetch(this,!0,t)._thenRunCallbacks(e)}},{key:"save",value:function(e,t,r){var n,o,a=this;if("object"===("undefined"==typeof e?"undefined":(0,y["default"])(e))||"undefined"==typeof e?(n=e,"object"===("undefined"==typeof t?"undefined":(0,y["default"])(t))&&(o=t)):(n={},n[e]=t,o=r),!o&&n&&(o={},"function"==typeof n.success&&(o.success=n.success,delete n.success),"function"==typeof n.error&&(o.error=n.error,delete n.error)),n){var i=this.validate(n);if(i)return o&&"function"==typeof o.error&&o.error(this,i),W["default"].error(i);this.set(n,o)}o=o||{};var s={};o.hasOwnProperty("useMasterKey")&&(s.useMasterKey=!!o.useMasterKey),o.hasOwnProperty("sessionToken")&&"string"==typeof o.sessionToken&&(s.sessionToken=o.sessionToken);var u=k["default"].getObjectController(),l=(0,te["default"])(this);return u.save(l,s).then(function(){return u.save(a,s)})._thenRunCallbacks(o,this)}},{key:"destroy",value:function(e){e=e||{};var t={};return e.hasOwnProperty("useMasterKey")&&(t.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(t.sessionToken=e.sessionToken),this.id?k["default"].getObjectController().destroy(this,t)._thenRunCallbacks(e):W["default"].as()._thenRunCallbacks(e)}},{key:"attributes",get:function(){var e=k["default"].getObjectStateController();return(0,f["default"])(e.estimateAttributes(this._getStateIdentifier()))}},{key:"createdAt",get:function(){return this._getServerData().createdAt}},{key:"updatedAt",get:function(){return this._getServerData().updatedAt}}],[{key:"_clearAllState",value:function(){var e=k["default"].getObjectStateController();e.clearAllState()}},{key:"fetchAll",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().fetch(e,!0,r)._thenRunCallbacks(t)}},{key:"fetchAllIfNeeded",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().fetch(e,!1,r)._thenRunCallbacks(t)}},{key:"destroyAll",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().destroy(e,r)._thenRunCallbacks(t)}},{key:"saveAll",value:function(e,t){var t=t||{},r={};return t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),k["default"].getObjectController().save(e,r)._thenRunCallbacks(t)}},{key:"createWithoutData",value:function(e){var t=new this;return t.id=e,t}},{key:"fromJSON",value:function(t,r){if(!t.className)throw new Error("Cannot create an object without a className");var n=re[t.className],o=n?new n:new e(t.className),a={};for(var i in t)"className"!==i&&"__type"!==i&&(a[i]=t[i]);if(r){a.objectId&&(o.id=a.objectId);var s=null;"function"==typeof o._preserveFieldsOnFetch&&(s=o._preserveFieldsOnFetch()),o._clearServerData(),s&&o._finishFetch(s)}return o._finishFetch(a),t.objectId&&o._setExisted(!0),o}},{key:"registerSubclass",value:function(e,t){if("string"!=typeof e)throw new TypeError("The first argument must be a valid class name.");if("undefined"==typeof t)throw new TypeError("You must supply a subclass constructor.");if("function"!=typeof t)throw new TypeError("You must register the subclass constructor. Did you attempt to register an instance of the subclass?");re[e]=t,t.className||(t.className=e)}},{key:"extend",value:function(t,r,n){if("string"!=typeof t){if(t&&"string"==typeof t.className)return e.extend(t.className,t,r);throw new Error("Parse.Object.extend's first argument should be the className.")}var o=t;"User"===o&&k["default"].get("PERFORM_USER_REWRITE")&&(o="_User");var a=e.prototype;this.hasOwnProperty("__super__")&&this.__super__?a=this.prototype:re[o]&&(a=re[o].prototype);var i=function(e,t){if(this.className=o,this._objCount=oe++,"function"==typeof this.initialize&&this.initialize.apply(this,arguments),e&&"object"===("undefined"==typeof e?"undefined":(0,y["default"])(e))&&!this.set(e||{},t))throw new Error("Can't create an invalid Parse Object")};if(i.className=o,i.__super__=a,i.prototype=(0,l["default"])(a,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}),r)for(var u in r)"className"!==u&&(0,s["default"])(i.prototype,u,{value:r[u],enumerable:!1,writable:!0,configurable:!0});if(n)for(var u in n)"className"!==u&&(0,s["default"])(i,u,{value:n[u],enumerable:!1,writable:!0,configurable:!0});return i.extend=function(t,r,n){return"string"==typeof t?e.extend.call(i,t,r,n):e.extend.call(i,o,t,r)},i.createWithoutData=e.createWithoutData,re[o]=i,i}},{key:"enableSingleInstance",value:function(){ae=!0,k["default"].setObjectStateController(Y)}},{key:"disableSingleInstance",value:function(){ae=!1,k["default"].setObjectStateController(Z)}}]),e}();r["default"]=ie;var se={fetch:function(e,t,r){if(Array.isArray(e)){if(e.length<1)return W["default"].as([]);var n=[],o=[],a=null,i=[],s=null;if(e.forEach(function(e,r){s||(a||(a=e.className),a!==e.className&&(s=new U["default"](U["default"].INVALID_CLASS_NAME,"All objects should be of the same class")),e.id||(s=new U["default"](U["default"].MISSING_OBJECT_ID,"All objects must have an ID")),(t||0===(0,_["default"])(e._getServerData()).length)&&(o.push(e.id),n.push(e)),i.push(e))}),s)return W["default"].error(s);var u=new B["default"](a);return u.containedIn("objectId",o),u._limit=o.length,u.find(r).then(function(e){var r={};e.forEach(function(e){r[e.id]=e});for(var o=0;o=20&&n.push([]))}),0===n[n.length-1].length&&n.pop();var o=W["default"].as(),i=[];return n.forEach(function(e){o=o.then(function(){return r.request("POST","batch",{requests:e.map(function(e){return{method:"DELETE",path:a()+"classes/"+e.className+"/"+e._getId(),body:{}}})},t).then(function(t){for(var r=0;r0},function(){var e=[],i=[];if(u.forEach(function(t){e.length<20&&(0,w["default"])(t)?e.push(t):i.push(t)}),u=i,e.length<1)return W["default"].error(new U["default"](U["default"].OTHER_CAUSE,"Tried to save a batch with a cycle."));var s=new W["default"],l=[],c=[];return e.forEach(function(e,t){var r=new W["default"];l.push(r),n.pushPendingState(e._getStateIdentifier()),c.push(n.enqueueTask(e._getStateIdentifier(),function(){return r.resolve(),s.then(function(r,n){if(r[t].hasOwnProperty("success"))e._handleSaveResponse(r[t].success,n);else{if(!o&&r[t].hasOwnProperty("error")){var a=r[t].error;o=new U["default"](a.code,a.error),u=[]}e._handleSaveError()}})}))}),W["default"].when(l).then(function(){return r.request("POST","batch",{requests:e.map(function(e){var t=e._getSaveParams();return t.path=a()+t.path,t})},t)}).then(function(e,t,r){s.resolve(e,t)}),W["default"].when(c)}).then(function(){return o?W["default"].error(o):W["default"].as(e)})})}if(e instanceof ie){var l=e,c=function(){var e=l._getSaveParams();return r.request(e.method,e.path,e.body,t).then(function(e,t){l._handleSaveResponse(e,t)},function(e){return l._handleSaveError(),W["default"].error(e)})};return n.pushPendingState(e._getStateIdentifier()),n.enqueueTask(e._getStateIdentifier(),c).then(function(){return e},function(e){return W["default"].error(e)})}return W["default"].as()}};k["default"].setObjectController(se)},{"./CoreManager":3,"./ParseACL":11,"./ParseError":13,"./ParseFile":14,"./ParseOp":19,"./ParsePromise":20,"./ParseQuery":21,"./ParseRelation":22,"./SingleInstanceStateController":28,"./UniqueInstanceStateController":32,"./canBeSerialized":34,"./decode":35,"./encode":36,"./equals":37,"./escape":38,"./parseDate":40,"./unique":41,"./unsavedChildren":42,"babel-runtime/core-js/json/stringify":44,"babel-runtime/core-js/object/create":46,"babel-runtime/core-js/object/define-property":47,"babel-runtime/core-js/object/freeze":48,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],19:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e){if(!e||!e.__op)return null;switch(e.__op){case"Delete":return new A;case"Increment":return new I(e.amount);case"Add":return new T((0,b["default"])(e.objects));case"AddUnique":return new N((0,b["default"])(e.objects));case"Remove":return new R((0,b["default"])(e.objects));case"AddRelation":var t=(0,b["default"])(e.objects);return Array.isArray(t)?new M(t,[]):new M([],[]);case"RemoveRelation":var r=(0,b["default"])(e.objects);return Array.isArray(r)?new M([],r):new M([],[]);case"Batch":for(var t=[],r=[],n=0;n-1;)r.splice(n,1),n=r.indexOf(this._value[t]);if(this._value[t]instanceof j["default"]&&this._value[t].id)for(var o=0;o-1&&r.splice(t,1)}),this.relationsToAdd.forEach(function(e){var t=r.indexOf(e);t<0&&r.push(e)});var n=e.relationsToRemove.concat([]);this.relationsToAdd.forEach(function(e){var t=n.indexOf(e);t>-1&&n.splice(t,1)}),this.relationsToRemove.forEach(function(e){var t=n.indexOf(e);t<0&&n.push(e)});var o=new t(r,n);return o._targetClassName=this._targetClassName,o}throw new Error("Cannot merge Relation Op with the previous Op")}},{key:"toJSON",value:function(){var e=this,t=function(t){return{__type:"Pointer",className:e._targetClassName,objectId:t}},r=null,n=null,o=null;return this.relationsToAdd.length>0&&(o=this.relationsToAdd.map(t),r={__op:"AddRelation",objects:o}),this.relationsToRemove.length>0&&(o=this.relationsToRemove.map(t),n={__op:"RemoveRelation",objects:o}),r&&n?{__op:"Batch",ops:[r,n]}:r||n||{}}}]),t}(E)},{"./ParseObject":18,"./ParseRelation":22,"./arrayContainsObject":33,"./decode":35,"./encode":36,"./unique":41,"babel-runtime/core-js/object/get-prototype-of":50,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/inherits":59,"babel-runtime/helpers/possibleConstructorReturn":60}],20:[function(e,t,r){(function(t){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}Object.defineProperty(r,"__esModule",{value:!0});var o=e("babel-runtime/core-js/get-iterator"),a=n(o),i=e("babel-runtime/helpers/typeof"),s=n(i),u=e("babel-runtime/helpers/classCallCheck"),l=n(u),c=e("babel-runtime/helpers/createClass"),f=n(c),d=!0,h=function(){function e(t){(0,l["default"])(this,e),this._resolved=!1,this._rejected=!1,this._resolvedCallbacks=[],this._rejectedCallbacks=[],"function"==typeof t&&t(this.resolve.bind(this),this.reject.bind(this))}return(0,f["default"])(e,[{key:"resolve",value:function(){if(this._resolved||this._rejected)throw new Error("A promise was resolved even though it had already been "+(this._resolved?"resolved":"rejected")+".");this._resolved=!0;for(var e=arguments.length,t=Array(e),r=0;r=r&&h.resolve(_)))},function(e){h.reject(e),d=!0}):(_[n]=t,p++,!d&&p>=r&&h.resolve(_))}),h}},{key:"race",value:function(t){var r=!1,n=new e,o=!0,i=!1,s=void 0;try{for(var u,l=(0,a["default"])(t);!(o=(u=l.next()).done);o=!0){var c=u.value;e.is(c)?c.then(function(e){r||(r=!0,n.resolve(e))},function(e){r||(r=!0,n.reject(e))}):r||(r=!0,n.resolve(c))}}catch(f){i=!0,s=f}finally{try{!o&&l["return"]&&l["return"]()}finally{if(i)throw s}}return n}},{key:"_continueWhile",value:function(t,r){return t()?r().then(function(){return e._continueWhile(t,r)}):e.as()}},{key:"isPromisesAPlusCompliant",value:function(){return d}},{key:"enableAPlusCompliant",value:function(){d=!0}},{key:"disableAPlusCompliant",value:function(){d=!1}}]),e}();r["default"]=h}).call(this,e("_process"))},{_process:168,"babel-runtime/core-js/get-iterator":43,"babel-runtime/helpers/classCallCheck":56,"babel-runtime/helpers/createClass":57,"babel-runtime/helpers/typeof":61}],21:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e){return"\\Q"+e.replace("\\E","\\E\\\\E\\Q")+"\\E"}function a(e,t){var r={};if(t.forEach(function(t){var n=t.indexOf(".")!==-1;if(n||e.hasOwnProperty(t)){if(n){var o=t.split("."),a=e,i=r;o.forEach(function(e,t,r){a[e]||(a[e]=t==r.length-1?void 0:{}),a=a[e],t0){var n=function a(e,t,r,n){if(n)for(var o in e)e.hasOwnProperty(o)&&!t.hasOwnProperty(o)&&(t[o]=e[o]);for(var o in r)a(e[o],t[o],r[o],!0)},o=_["default"].getObjectStateController().getServerData({id:e.objectId,className:e.className});n(o,e,r,!1)}}Object.defineProperty(r,"__esModule",{value:!0});var i=e("babel-runtime/helpers/typeof"),s=n(i),u=e("babel-runtime/helpers/classCallCheck"),l=n(u),c=e("babel-runtime/helpers/createClass"),f=n(c),d=e("babel-runtime/core-js/object/keys"),h=n(d),p=e("./CoreManager"),_=n(p),v=e("./encode"),y=n(v),b=e("./ParseError"),g=n(b),m=e("./ParseGeoPoint"),C=n(m),j=e("./ParseObject"),k=n(j),O=e("./ParsePromise"),w=n(O),S=function(){function e(t){if((0,l["default"])(this,e),"string"==typeof t)"User"===t&&_["default"].get("PERFORM_USER_REWRITE")?this.className="_User":this.className=t;else if(t instanceof k["default"])this.className=t.className;else{if("function"!=typeof t)throw new TypeError("A ParseQuery must be constructed with a ParseObject or class name.");if("string"==typeof t.className)this.className=t.className;else{var r=new t;this.className=r.className}}this._where={},this._include=[],this._limit=-1,this._skip=0,this._extraOptions={}}return(0,f["default"])(e,[{key:"_orQuery",value:function(e){var t=e.map(function(e){return e.toJSON().where});return this._where.$or=t,this}},{key:"_addCondition",value:function(e,t,r){return this._where[e]&&"string"!=typeof this._where[e]||(this._where[e]={}),this._where[e][t]=(0,y["default"])(r,!1,!0),this}},{key:"_regexStartWith",value:function(e){return"^"+o(e)}},{key:"toJSON",value:function(){var e={where:this._where};this._include.length&&(e.include=this._include.join(",")),this._select&&(e.keys=this._select.join(",")),this._limit>=0&&(e.limit=this._limit),this._skip>0&&(e.skip=this._skip),this._order&&(e.order=this._order.join(","));for(var t in this._extraOptions)e[t]=this._extraOptions[t];return e}},{key:"get",value:function(e,t){this.equalTo("objectId",e);var r={};return t&&t.hasOwnProperty("useMasterKey")&&(r.useMasterKey=t.useMasterKey),t&&t.hasOwnProperty("sessionToken")&&(r.sessionToken=t.sessionToken),this.first(r).then(function(e){if(e)return e;var t=new g["default"](g["default"].OBJECT_NOT_FOUND,"Object not found.");return w["default"].error(t)})._thenRunCallbacks(t,null)}},{key:"find",value:function(e){var t=this;e=e||{};var r={};e.hasOwnProperty("useMasterKey")&&(r.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(r.sessionToken=e.sessionToken);var n=_["default"].getQueryController(),o=this._select;return n.find(this.className,this.toJSON(),r).then(function(e){return e.results.map(function(r){var n=e.className||t.className;return r.className||(r.className=n),o&&a(r,o),k["default"].fromJSON(r,!o)})})._thenRunCallbacks(e)}},{key:"count",value:function(e){e=e||{};var t={};e.hasOwnProperty("useMasterKey")&&(t.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(t.sessionToken=e.sessionToken);var r=_["default"].getQueryController(),n=this.toJSON();return n.limit=0,n.count=1,r.find(this.className,n,t).then(function(e){return e.count})._thenRunCallbacks(e)}},{key:"first",value:function(e){var t=this;e=e||{};var r={};e.hasOwnProperty("useMasterKey")&&(r.useMasterKey=e.useMasterKey),e.hasOwnProperty("sessionToken")&&(r.sessionToken=e.sessionToken);var n=_["default"].getQueryController(),o=this.toJSON();o.limit=1;var i=this._select;return n.find(this.className,o,r).then(function(e){var r=e.results;if(r[0])return r[0].className||(r[0].className=t.className),i&&a(r[0],i),k["default"].fromJSON(r[0],!i)})._thenRunCallbacks(e)}},{key:"each",value:function(t,r){if(r=r||{},this._order||this._skip||this._limit>=0)return w["default"].error("Cannot iterate on a query with sort, skip, or limit.")._thenRunCallbacks(r);new w["default"];var n=new e(this.className);n._limit=r.batchSize||100,n._include=this._include.map(function(e){return e}),this._select&&(n._select=this._select.map(function(e){return e})),n._where={};for(var o in this._where){var a=this._where[o];if(Array.isArray(a))n._where[o]=a.map(function(e){return e});else if(a&&"object"===("undefined"==typeof a?"undefined":(0,s["default"])(a))){var i={};n._where[o]=i;for(var u in a)i[u]=a[u]}else n._where[o]=a}n.ascending("objectId");var l={};r.hasOwnProperty("useMasterKey")&&(l.useMasterKey=r.useMasterKey),r.hasOwnProperty("sessionToken")&&(l.sessionToken=r.sessionToken);var c=!1;return w["default"]._continueWhile(function(){return!c},function(){return n.find(l).then(function(e){var r=w["default"].as();return e.forEach(function(e){r=r.then(function(){return t(e)})}),r.then(function(){e.length>=n._limit?n.greaterThan("objectId",e[e.length-1].id):c=!0})})})._thenRunCallbacks(r)}},{key:"equalTo",value:function(e,t){return"undefined"==typeof t?this.doesNotExist(e):(this._where[e]=(0,y["default"])(t,!1,!0),this)}},{key:"notEqualTo",value:function(e,t){return this._addCondition(e,"$ne",t)}},{key:"lessThan",value:function(e,t){return this._addCondition(e,"$lt",t)}},{key:"greaterThan",value:function(e,t){return this._addCondition(e,"$gt",t)}},{key:"lessThanOrEqualTo",value:function(e,t){return this._addCondition(e,"$lte",t)}},{key:"greaterThanOrEqualTo",value:function(e,t){return this._addCondition(e,"$gte",t)}},{key:"containedIn",value:function(e,t){return this._addCondition(e,"$in",t)}},{key:"notContainedIn",value:function(e,t){return this._addCondition(e,"$nin",t)}},{key:"containsAll",value:function(e,t){return this._addCondition(e,"$all",t)}},{key:"containsAllStartingWith",value:function(e,t){var r=this;return Array.isArray(t)||(t=[t]),t=t.map(function(e){return{$regex:r._regexStartWith(e)}}),this.containsAll(e,t)}},{key:"exists",value:function(e){return this._addCondition(e,"$exists",!0)}},{key:"doesNotExist",value:function(e){return this._addCondition(e,"$exists",!1)}},{key:"matches",value:function(e,t,r){return this._addCondition(e,"$regex",t),r||(r=""),t.ignoreCase&&(r+="i"),t.multiline&&(r+="m"),r.length&&this._addCondition(e,"$options",r),this}},{key:"matchesQuery",value:function(e,t){var r=t.toJSON();return r.className=t.className,this._addCondition(e,"$inQuery",r)}},{key:"doesNotMatchQuery",value:function(e,t){var r=t.toJSON();return r.className=t.className,this._addCondition(e,"$notInQuery",r)}},{key:"matchesKeyInQuery",value:function(e,t,r){var n=r.toJSON();return n.className=r.className,this._addCondition(e,"$select",{key:t,query:n})}},{key:"doesNotMatchKeyInQuery",value:function(e,t,r){var n=r.toJSON();return n.className=r.className,this._addCondition(e,"$dontSelect",{key:t,query:n})}},{key:"contains",value:function(e,t){if("string"!=typeof t)throw new Error("The value being searched for must be a string.");return this._addCondition(e,"$regex",o(t))}},{key:"startsWith",value:function(e,t){if("string"!=typeof t)throw new Error("The value being searched for must be a string.");return this._addCondition(e,"$regex",this._regexStartWith(t))}},{key:"endsWith",value:function(e,t){if("string"!=typeof t)throw new Error("The value being searched for must be a string.");return this._addCondition(e,"$regex",o(t)+"$")}},{key:"near",value:function(e,t){return t instanceof C["default"]||(t=new C["default"](t)),this._addCondition(e,"$nearSphere",t)}},{key:"withinRadians",value:function(e,t,r){return this.near(e,t),this._addCondition(e,"$maxDistance",r)}},{key:"withinMiles",value:function(e,t,r){return this.withinRadians(e,t,r/3958.8)}},{key:"withinKilometers",value:function(e,t,r){return this.withinRadians(e,t,r/6371)}},{key:"withinGeoBox",value:function(e,t,r){return t instanceof C["default"]||(t=new C["default"](t)),r instanceof C["default"]||(r=new C["default"](r)),this._addCondition(e,"$within",{$box:[t,r]}),this}},{key:"ascending",value:function(){this._order=[];for(var e=arguments.length,t=Array(e),r=0;r=200&&l.status<300){var e;try{e=JSON.parse(l.responseText)}catch(t){i.reject(t.toString())}e&&i.resolve(e,l.status,l)}else if(l.status>=500||0===l.status)if(++s-1)return!0;for(var r=0;r-1||e.dirty()||(0,u["default"])(e._getServerData()).length<1?e.toPointer():(n=n.concat(a),e._toFullJSON(n))}if(e instanceof y.Op||e instanceof c["default"]||e instanceof p["default"]||e instanceof g["default"])return e.toJSON();if(e instanceof d["default"]){if(!e.url())throw new Error("Tried to encode an unsaved file.");return e.toJSON()}if("[object Date]"===m.call(e)){if(isNaN(e))throw new Error("Tried to encode an invalid date.");return{__type:"Date",iso:e.toJSON()}}if("[object RegExp]"===m.call(e)&&"string"==typeof e.source)return e.source;if(Array.isArray(e))return e.map(function(e){return o(e,t,r,n)});if(e&&"object"===("undefined"==typeof e?"undefined":(0,i["default"])(e))){var s={};for(var l in e)s[l]=o(e[l],t,r,n);return s}return e}Object.defineProperty(r,"__esModule",{value:!0});var a=e("babel-runtime/helpers/typeof"),i=n(a),s=e("babel-runtime/core-js/object/keys"),u=n(s);r["default"]=function(e,t,r,n){return o(e,!!t,!!r,n||[])};var l=e("./ParseACL"),c=n(l),f=e("./ParseFile"),d=n(f),h=e("./ParseGeoPoint"),p=n(h),_=e("./ParseObject"),v=n(_),y=e("./ParseOp"),b=e("./ParseRelation"),g=n(b),m=Object.prototype.toString},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"./ParseOp":19,"./ParseRelation":22,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],37:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){if(("undefined"==typeof e?"undefined":(0,u["default"])(e))!==("undefined"==typeof t?"undefined":(0,u["default"])(t)))return!1;if(!e||"object"!==("undefined"==typeof e?"undefined":(0,u["default"])(e)))return e===t;if(Array.isArray(e)||Array.isArray(t)){if(!Array.isArray(e)||!Array.isArray(t))return!1;if(e.length!==t.length)return!1;for(var r=e.length;r--;)if(!o(e[r],t[r]))return!1;return!0}if(e instanceof c["default"]||e instanceof d["default"]||e instanceof p["default"]||e instanceof v["default"])return e.equals(t);if((0,i["default"])(e).length!==(0,i["default"])(t).length)return!1;for(var n in e)if(!o(e[n],t[n]))return!1;return!0}Object.defineProperty(r,"__esModule",{value:!0});var a=e("babel-runtime/core-js/object/keys"),i=n(a),s=e("babel-runtime/helpers/typeof"),u=n(s);r["default"]=o;var l=e("./ParseACL"),c=n(l),f=e("./ParseFile"),d=n(f),h=e("./ParseGeoPoint"),p=n(h),_=e("./ParseObject"),v=n(_)},{"./ParseACL":11,"./ParseFile":14,"./ParseGeoPoint":15,"./ParseObject":18,"babel-runtime/core-js/object/keys":51,"babel-runtime/helpers/typeof":61}],38:[function(e,t,r){"use strict";function n(e){return e.replace(/[&<>\/'"]/g,function(e){return o[e]})}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=n;var o={"&":"&","<":"<",">":">","/":"/","'":"'",'"':"""}},{}],39:[function(e,t,r){"use strict";function n(e){return e.indexOf("r:")>-1}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=n},{}],40:[function(e,t,r){"use strict";function n(e){var t=new RegExp("^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})T([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})(.([0-9]+))?Z$"),r=t.exec(e);if(!r)return null;var n=r[1]||0,o=(r[2]||1)-1,a=r[3]||0,i=r[4]||0,s=r[5]||0,u=r[6]||0,l=r[8]||0;return new Date(Date.UTC(n,o,a,i,s,u,l))}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=n},{}],41:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e){var t=[];return e.forEach(function(e){e instanceof u["default"]?(0,i["default"])(t,e)||t.push(e):t.indexOf(e)<0&&t.push(e)}),t}Object.defineProperty(r,"__esModule",{value:!0}),r["default"]=o;var a=e("./arrayContainsObject"),i=n(a),s=e("./ParseObject"),u=n(s)},{"./ParseObject":18,"./arrayContainsObject":33}],42:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}function o(e,t){var r={objects:{},files:[]},n=e.className+":"+e._getId();r.objects[n]=!e.dirty()||e;var o=e.attributes;for(var i in o)"object"===(0,s["default"])(o[i])&&a(o[i],r,!1,!!t);var u=[];for(var l in r.objects)l!==n&&r.objects[l]!==!0&&u.push(r.objects[l]);return u.concat(r.files)}function a(e,t,r,n){if(e instanceof f["default"]){if(!e.id&&r)throw new Error("Cannot create a pointer to an unsaved Object.");var o=e.className+":"+e._getId();if(!t.objects[o]){t.objects[o]=!e.dirty()||e;var i=e.attributes;for(var u in i)"object"===(0,s["default"])(i[u])&&a(i[u],t,!n,n)}}else{if(e instanceof l["default"])return void(!e.url()&&t.files.indexOf(e)<0&&t.files.push(e));if(!(e instanceof h["default"])){Array.isArray(e)&&e.forEach(function(e){"object"===("undefined"==typeof e?"undefined":(0,s["default"])(e))&&a(e,t,r,n)});for(var c in e)"object"===(0,s["default"])(e[c])&&a(e[c],t,r,n)}}}Object.defineProperty(r,"__esModule",{value:!0});var i=e("babel-runtime/helpers/typeof"),s=n(i);r["default"]=o;var u=e("./ParseFile"),l=n(u),c=e("./ParseObject"),f=n(c),d=e("./ParseRelation"),h=n(d)},{"./ParseFile":14,"./ParseObject":18,"./ParseRelation":22,"babel-runtime/helpers/typeof":61}],43:[function(e,t,r){t.exports={"default":e("core-js/library/fn/get-iterator"),__esModule:!0}},{"core-js/library/fn/get-iterator":62}],44:[function(e,t,r){t.exports={"default":e("core-js/library/fn/json/stringify"),__esModule:!0}},{"core-js/library/fn/json/stringify":63}],45:[function(e,t,r){t.exports={"default":e("core-js/library/fn/map"),__esModule:!0}},{"core-js/library/fn/map":64}],46:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/create"),__esModule:!0}},{"core-js/library/fn/object/create":65}],47:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/define-property"),__esModule:!0}},{"core-js/library/fn/object/define-property":66}],48:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/freeze"),__esModule:!0}},{"core-js/library/fn/object/freeze":67}],49:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/get-own-property-descriptor"),__esModule:!0}},{"core-js/library/fn/object/get-own-property-descriptor":68}],50:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/get-prototype-of"),__esModule:!0}},{"core-js/library/fn/object/get-prototype-of":69}],51:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/keys"),__esModule:!0}},{"core-js/library/fn/object/keys":70}],52:[function(e,t,r){t.exports={"default":e("core-js/library/fn/object/set-prototype-of"),__esModule:!0}},{"core-js/library/fn/object/set-prototype-of":71}],53:[function(e,t,r){t.exports={"default":e("core-js/library/fn/symbol"),__esModule:!0}},{"core-js/library/fn/symbol":72}],54:[function(e,t,r){t.exports={"default":e("core-js/library/fn/symbol/iterator"),__esModule:!0}},{"core-js/library/fn/symbol/iterator":73}],55:[function(e,t,r){t.exports={"default":e("core-js/library/fn/weak-map"),__esModule:!0}},{"core-js/library/fn/weak-map":74}],56:[function(e,t,r){"use strict";r.__esModule=!0,r["default"]=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},{}],57:[function(e,t,r){"use strict";function n(e){return e&&e.__esModule?e:{"default":e}}r.__esModule=!0;var o=e("../core-js/object/define-property"),a=n(o);r["default"]=function(){function e(e,t){for(var r=0;rc;)if(s=u[c++],s!=s)return!0}else for(;l>c;c++)if((e||c in u)&&u[c]===r)return e||c||0;return!e&&-1}}},{"./_to-index":139,"./_to-iobject":141,"./_to-length":142}],81:[function(e,t,r){var n=e("./_ctx"),o=e("./_iobject"),a=e("./_to-object"),i=e("./_to-length"),s=e("./_array-species-create");t.exports=function(e,t){var r=1==e,u=2==e,l=3==e,c=4==e,f=6==e,d=5==e||f,h=t||s;return function(t,s,p){for(var _,v,y=a(t),b=o(y),g=n(s,p,3),m=i(b.length),C=0,j=r?h(t,m):u?h(t,0):void 0;m>C;C++)if((d||C in b)&&(_=b[C],v=g(_,C,y),e))if(r)j[C]=v;else if(v)switch(e){case 3:return!0;case 5:return _;case 6:return C;case 2:j.push(_)}else if(c)return!1;return f?-1:l||c?c:j}}},{"./_array-species-create":83,"./_ctx":91,"./_iobject":105,"./_to-length":142,"./_to-object":143}],82:[function(e,t,r){var n=e("./_is-object"),o=e("./_is-array"),a=e("./_wks")("species");t.exports=function(e){var t;return o(e)&&(t=e.constructor,"function"!=typeof t||t!==Array&&!o(t.prototype)||(t=void 0),n(t)&&(t=t[a],null===t&&(t=void 0))),void 0===t?Array:t}},{"./_is-array":107,"./_is-object":108,"./_wks":148}],83:[function(e,t,r){var n=e("./_array-species-constructor");t.exports=function(e,t){return new(n(e))(t)}},{"./_array-species-constructor":82}],84:[function(e,t,r){var n=e("./_cof"),o=e("./_wks")("toStringTag"),a="Arguments"==n(function(){return arguments}()),i=function(e,t){try{return e[t]}catch(r){}};t.exports=function(e){var t,r,s;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(r=i(t=Object(e),o))?r:a?n(t):"Object"==(s=n(t))&&"function"==typeof t.callee?"Arguments":s}},{"./_cof":85,"./_wks":148}],85:[function(e,t,r){var n={}.toString;t.exports=function(e){return n.call(e).slice(8,-1)}},{}],86:[function(e,t,r){"use strict";var n=e("./_object-dp").f,o=e("./_object-create"),a=e("./_redefine-all"),i=e("./_ctx"),s=e("./_an-instance"),u=e("./_defined"),l=e("./_for-of"),c=e("./_iter-define"),f=e("./_iter-step"),d=e("./_set-species"),h=e("./_descriptors"),p=e("./_meta").fastKey,_=h?"_s":"size",v=function(e,t){var r,n=p(t);if("F"!==n)return e._i[n];for(r=e._f;r;r=r.n)if(r.k==t)return r};t.exports={getConstructor:function(e,t,r,c){var f=e(function(e,n){s(e,f,t,"_i"),e._i=o(null),e._f=void 0,e._l=void 0,e[_]=0,void 0!=n&&l(n,r,e[c],e)});return a(f.prototype,{clear:function(){for(var e=this,t=e._i,r=e._f;r;r=r.n)r.r=!0,r.p&&(r.p=r.p.n=void 0),delete t[r.i];e._f=e._l=void 0,e[_]=0},"delete":function(e){var t=this,r=v(t,e);if(r){var n=r.n,o=r.p;delete t._i[r.i],r.r=!0,o&&(o.n=n),n&&(n.p=o),t._f==r&&(t._f=n),t._l==r&&(t._l=o),t[_]--}return!!r},forEach:function(e){s(this,f,"forEach");for(var t,r=i(e,arguments.length>1?arguments[1]:void 0,3);t=t?t.n:this._f;)for(r(t.v,t.k,this);t&&t.r;)t=t.p},has:function(e){return!!v(this,e)}}),h&&n(f.prototype,"size",{get:function(){return u(this[_])}}),f},def:function(e,t,r){var n,o,a=v(e,t);return a?a.v=r:(e._l=a={i:o=p(t,!0),k:t,v:r,p:n=e._l,n:void 0,r:!1},e._f||(e._f=a),n&&(n.n=a),e[_]++,"F"!==o&&(e._i[o]=a)),e},getEntry:v,setStrong:function(e,t,r){c(e,t,function(e,t){this._t=e,this._k=t,this._l=void 0},function(){for(var e=this,t=e._k,r=e._l;r&&r.r;)r=r.p;return e._t&&(e._l=r=r?r.n:e._t._f)?"keys"==t?f(0,r.k):"values"==t?f(0,r.v):f(0,[r.k,r.v]):(e._t=void 0,f(1))},r?"entries":"values",!r,!0),d(t)}}},{"./_an-instance":77,"./_ctx":91,"./_defined":92,"./_descriptors":93,"./_for-of":99,"./_iter-define":111,"./_iter-step":112,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_redefine-all":131,"./_set-species":134}],87:[function(e,t,r){var n=e("./_classof"),o=e("./_array-from-iterable");t.exports=function(e){return function(){if(n(this)!=e)throw TypeError(e+"#toJSON isn't generic");return o(this)}}},{"./_array-from-iterable":79,"./_classof":84}],88:[function(e,t,r){"use strict";var n=e("./_redefine-all"),o=e("./_meta").getWeak,a=e("./_an-object"),i=e("./_is-object"),s=e("./_an-instance"),u=e("./_for-of"),l=e("./_array-methods"),c=e("./_has"),f=l(5),d=l(6),h=0,p=function(e){return e._l||(e._l=new _)},_=function(){this.a=[]},v=function(e,t){return f(e.a,function(e){return e[0]===t})};_.prototype={get:function(e){var t=v(this,e);if(t)return t[1]},has:function(e){return!!v(this,e)},set:function(e,t){var r=v(this,e);r?r[1]=t:this.a.push([e,t])},"delete":function(e){var t=d(this.a,function(t){return t[0]===e});return~t&&this.a.splice(t,1),!!~t}},t.exports={getConstructor:function(e,t,r,a){var l=e(function(e,n){s(e,l,t,"_i"),e._i=h++,e._l=void 0,void 0!=n&&u(n,r,e[a],e)});return n(l.prototype,{"delete":function(e){if(!i(e))return!1;var t=o(e);return t===!0?p(this)["delete"](e):t&&c(t,this._i)&&delete t[this._i]},has:function(e){if(!i(e))return!1;var t=o(e);return t===!0?p(this).has(e):t&&c(t,this._i)}}),l},def:function(e,t,r){var n=o(a(t),!0);return n===!0?p(e).set(t,r):n[e._i]=r,e},ufstore:p}},{"./_an-instance":77,"./_an-object":78,"./_array-methods":81,"./_for-of":99,"./_has":101,"./_is-object":108,"./_meta":116,"./_redefine-all":131}],89:[function(e,t,r){"use strict";var n=e("./_global"),o=e("./_export"),a=e("./_meta"),i=e("./_fails"),s=e("./_hide"),u=e("./_redefine-all"),l=e("./_for-of"),c=e("./_an-instance"),f=e("./_is-object"),d=e("./_set-to-string-tag"),h=e("./_object-dp").f,p=e("./_array-methods")(0),_=e("./_descriptors");t.exports=function(e,t,r,v,y,b){var g=n[e],m=g,C=y?"set":"add",j=m&&m.prototype,k={};return _&&"function"==typeof m&&(b||j.forEach&&!i(function(){(new m).entries().next()}))?(m=t(function(t,r){c(t,m,e,"_c"),t._c=new g,void 0!=r&&l(r,y,t[C],t)}),p("add,clear,delete,forEach,get,has,set,keys,values,entries,toJSON".split(","),function(e){var t="add"==e||"set"==e;e in j&&(!b||"clear"!=e)&&s(m.prototype,e,function(r,n){if(c(this,m,e),!t&&b&&!f(r))return"get"==e&&void 0;var o=this._c[e](0===r?0:r,n);return t?this:o})}),"size"in j&&h(m.prototype,"size",{get:function(){return this._c.size}})):(m=v.getConstructor(t,e,y,C),u(m.prototype,r),a.NEED=!0),d(m,e),k[e]=m,o(o.G+o.W+o.F,k),b||v.setStrong(m,e,y),m}},{"./_an-instance":77,"./_array-methods":81,"./_descriptors":93,"./_export":97,"./_fails":98,"./_for-of":99,"./_global":100,"./_hide":102,"./_is-object":108,"./_meta":116,"./_object-dp":119,"./_redefine-all":131,"./_set-to-string-tag":135}],90:[function(e,t,r){var n=t.exports={version:"2.4.0"};"number"==typeof __e&&(__e=n)},{}],91:[function(e,t,r){var n=e("./_a-function");t.exports=function(e,t,r){if(n(e),void 0===t)return e;switch(r){case 1:return function(r){return e.call(t,r)};case 2:return function(r,n){return e.call(t,r,n)};case 3:return function(r,n,o){return e.call(t,r,n,o)}}return function(){return e.apply(t,arguments)}}},{"./_a-function":75}],92:[function(e,t,r){t.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},{}],93:[function(e,t,r){t.exports=!e("./_fails")(function(){return 7!=Object.defineProperty({},"a",{get:function(){return 7}}).a})},{"./_fails":98}],94:[function(e,t,r){var n=e("./_is-object"),o=e("./_global").document,a=n(o)&&n(o.createElement);t.exports=function(e){return a?o.createElement(e):{}}},{"./_global":100,"./_is-object":108}],95:[function(e,t,r){t.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},{}],96:[function(e,t,r){var n=e("./_object-keys"),o=e("./_object-gops"),a=e("./_object-pie");t.exports=function(e){var t=n(e),r=o.f;if(r)for(var i,s=r(e),u=a.f,l=0;s.length>l;)u.call(e,i=s[l++])&&t.push(i);return t}},{"./_object-gops":124,"./_object-keys":127,"./_object-pie":128}],97:[function(e,t,r){var n=e("./_global"),o=e("./_core"),a=e("./_ctx"),i=e("./_hide"),s="prototype",u=function(e,t,r){var l,c,f,d=e&u.F,h=e&u.G,p=e&u.S,_=e&u.P,v=e&u.B,y=e&u.W,b=h?o:o[t]||(o[t]={}),g=b[s],m=h?n:p?n[t]:(n[t]||{})[s];h&&(r=t);for(l in r)c=!d&&m&&void 0!==m[l],c&&l in b||(f=c?m[l]:r[l],b[l]=h&&"function"!=typeof m[l]?r[l]:v&&c?a(f,n):y&&m[l]==f?function(e){var t=function(t,r,n){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,r)}return new e(t,r,n)}return e.apply(this,arguments)};return t[s]=e[s],t}(f):_&&"function"==typeof f?a(Function.call,f):f,_&&((b.virtual||(b.virtual={}))[l]=f,e&u.R&&g&&!g[l]&&i(g,l,f)))};u.F=1,u.G=2,u.S=4,u.P=8,u.B=16,u.W=32,u.U=64,u.R=128,t.exports=u},{"./_core":90,"./_ctx":91,"./_global":100,"./_hide":102}],98:[function(e,t,r){t.exports=function(e){try{return!!e()}catch(t){return!0}}},{}],99:[function(e,t,r){var n=e("./_ctx"),o=e("./_iter-call"),a=e("./_is-array-iter"),i=e("./_an-object"),s=e("./_to-length"),u=e("./core.get-iterator-method"),l={},c={},r=t.exports=function(e,t,r,f,d){var h,p,_,v,y=d?function(){return e}:u(e),b=n(r,f,t?2:1),g=0;if("function"!=typeof y)throw TypeError(e+" is not iterable!");if(a(y)){for(h=s(e.length);h>g;g++)if(v=t?b(i(p=e[g])[0],p[1]):b(e[g]),v===l||v===c)return v}else for(_=y.call(e);!(p=_.next()).done;)if(v=o(_,b,p.value,t),v===l||v===c)return v};r.BREAK=l,r.RETURN=c},{"./_an-object":78,"./_ctx":91,"./_is-array-iter":106,"./_iter-call":109,"./_to-length":142,"./core.get-iterator-method":149}],100:[function(e,t,r){var n=t.exports="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();"number"==typeof __g&&(__g=n)},{}],101:[function(e,t,r){var n={}.hasOwnProperty;t.exports=function(e,t){return n.call(e,t)}},{}],102:[function(e,t,r){var n=e("./_object-dp"),o=e("./_property-desc");t.exports=e("./_descriptors")?function(e,t,r){return n.f(e,t,o(1,r))}:function(e,t,r){return e[t]=r,e}},{"./_descriptors":93,"./_object-dp":119,"./_property-desc":130}],103:[function(e,t,r){t.exports=e("./_global").document&&document.documentElement},{"./_global":100}],104:[function(e,t,r){t.exports=!e("./_descriptors")&&!e("./_fails")(function(){return 7!=Object.defineProperty(e("./_dom-create")("div"),"a",{get:function(){return 7}}).a})},{"./_descriptors":93,"./_dom-create":94,"./_fails":98}],105:[function(e,t,r){var n=e("./_cof");t.exports=Object("z").propertyIsEnumerable(0)?Object:function(e){return"String"==n(e)?e.split(""):Object(e)}},{"./_cof":85}],106:[function(e,t,r){var n=e("./_iterators"),o=e("./_wks")("iterator"),a=Array.prototype;t.exports=function(e){return void 0!==e&&(n.Array===e||a[o]===e)}},{"./_iterators":113,"./_wks":148}],107:[function(e,t,r){var n=e("./_cof");t.exports=Array.isArray||function(e){return"Array"==n(e)}},{"./_cof":85}],108:[function(e,t,r){t.exports=function(e){return"object"==typeof e?null!==e:"function"==typeof e}},{}],109:[function(e,t,r){var n=e("./_an-object");t.exports=function(e,t,r,o){try{return o?t(n(r)[0],r[1]):t(r)}catch(a){var i=e["return"];throw void 0!==i&&n(i.call(e)),a}}},{"./_an-object":78}],110:[function(e,t,r){"use strict";var n=e("./_object-create"),o=e("./_property-desc"),a=e("./_set-to-string-tag"),i={};e("./_hide")(i,e("./_wks")("iterator"),function(){return this}),t.exports=function(e,t,r){e.prototype=n(i,{next:o(1,r)}),a(e,t+" Iterator")}},{"./_hide":102,"./_object-create":118,"./_property-desc":130,"./_set-to-string-tag":135,"./_wks":148}],111:[function(e,t,r){"use strict";var n=e("./_library"),o=e("./_export"),a=e("./_redefine"),i=e("./_hide"),s=e("./_has"),u=e("./_iterators"),l=e("./_iter-create"),c=e("./_set-to-string-tag"),f=e("./_object-gpo"),d=e("./_wks")("iterator"),h=!([].keys&&"next"in[].keys()),p="@@iterator",_="keys",v="values",y=function(){return this};t.exports=function(e,t,r,b,g,m,C){l(r,t,b);var j,k,O,w=function(e){if(!h&&e in A)return A[e];switch(e){case _:return function(){return new r(this,e)};case v:return function(){return new r(this,e)}}return function(){return new r(this,e)}},S=t+" Iterator",E=g==v,P=!1,A=e.prototype,I=A[d]||A[p]||g&&A[g],T=I||w(g),N=g?E?w("entries"):T:void 0,R="Array"==t?A.entries||I:I;if(R&&(O=f(R.call(new e)),O!==Object.prototype&&(c(O,S,!0),n||s(O,d)||i(O,d,y))),E&&I&&I.name!==v&&(P=!0,T=function(){return I.call(this)}),n&&!C||!h&&!P&&A[d]||i(A,d,T),u[t]=T,u[S]=y,g)if(j={values:E?T:w(v),keys:m?T:w(_),entries:N},C)for(k in j)k in A||a(A,k,j[k]);else o(o.P+o.F*(h||P),t,j);return j}},{"./_export":97,"./_has":101,"./_hide":102,"./_iter-create":110,"./_iterators":113,"./_library":115,"./_object-gpo":125,"./_redefine":132,"./_set-to-string-tag":135,"./_wks":148}],112:[function(e,t,r){t.exports=function(e,t){return{value:t,done:!!e}}},{}],113:[function(e,t,r){t.exports={}},{}],114:[function(e,t,r){var n=e("./_object-keys"),o=e("./_to-iobject");t.exports=function(e,t){for(var r,a=o(e),i=n(a),s=i.length,u=0;s>u;)if(a[r=i[u++]]===t)return r}},{"./_object-keys":127,"./_to-iobject":141}],115:[function(e,t,r){t.exports=!0},{}],116:[function(e,t,r){var n=e("./_uid")("meta"),o=e("./_is-object"),a=e("./_has"),i=e("./_object-dp").f,s=0,u=Object.isExtensible||function(){return!0},l=!e("./_fails")(function(){return u(Object.preventExtensions({}))}),c=function(e){i(e,n,{value:{i:"O"+ ++s,w:{}}})},f=function(e,t){if(!o(e))return"symbol"==typeof e?e:("string"==typeof e?"S":"P")+e;if(!a(e,n)){if(!u(e))return"F";if(!t)return"E";c(e)}return e[n].i},d=function(e,t){if(!a(e,n)){if(!u(e))return!0;if(!t)return!1;c(e)}return e[n].w},h=function(e){return l&&p.NEED&&u(e)&&!a(e,n)&&c(e),e},p=t.exports={KEY:n,NEED:!1,fastKey:f,getWeak:d,onFreeze:h}},{"./_fails":98,"./_has":101,"./_is-object":108,"./_object-dp":119,"./_uid":145}],117:[function(e,t,r){"use strict";var n=e("./_object-keys"),o=e("./_object-gops"),a=e("./_object-pie"),i=e("./_to-object"),s=e("./_iobject"),u=Object.assign;t.exports=!u||e("./_fails")(function(){var e={},t={},r=Symbol(),n="abcdefghijklmnopqrst";return e[r]=7,n.split("").forEach(function(e){t[e]=e}),7!=u({},e)[r]||Object.keys(u({},t)).join("")!=n})?function(e,t){for(var r=i(e),u=arguments.length,l=1,c=o.f,f=a.f;u>l;)for(var d,h=s(arguments[l++]),p=c?n(h).concat(c(h)):n(h),_=p.length,v=0;_>v;)f.call(h,d=p[v++])&&(r[d]=h[d]);return r}:u},{"./_fails":98,"./_iobject":105,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_to-object":143}],118:[function(e,t,r){var n=e("./_an-object"),o=e("./_object-dps"),a=e("./_enum-bug-keys"),i=e("./_shared-key")("IE_PROTO"),s=function(){},u="prototype",l=function(){var t,r=e("./_dom-create")("iframe"),n=a.length,o="<",i=">";for(r.style.display="none",e("./_html").appendChild(r),r.src="javascript:",t=r.contentWindow.document,t.open(),t.write(o+"script"+i+"document.F=Object"+o+"/script"+i),t.close(),l=t.F;n--;)delete l[u][a[n]];return l()};t.exports=Object.create||function(e,t){var r;return null!==e?(s[u]=n(e),r=new s,s[u]=null,r[i]=e):r=l(),void 0===t?r:o(r,t)}},{"./_an-object":78,"./_dom-create":94,"./_enum-bug-keys":95,"./_html":103,"./_object-dps":120,"./_shared-key":136}],119:[function(e,t,r){var n=e("./_an-object"),o=e("./_ie8-dom-define"),a=e("./_to-primitive"),i=Object.defineProperty;r.f=e("./_descriptors")?Object.defineProperty:function(e,t,r){if(n(e),t=a(t,!0),n(r),o)try{return i(e,t,r)}catch(s){}if("get"in r||"set"in r)throw TypeError("Accessors not supported!");return"value"in r&&(e[t]=r.value),e}},{"./_an-object":78,"./_descriptors":93,"./_ie8-dom-define":104,"./_to-primitive":144}],120:[function(e,t,r){var n=e("./_object-dp"),o=e("./_an-object"),a=e("./_object-keys");t.exports=e("./_descriptors")?Object.defineProperties:function(e,t){o(e);for(var r,i=a(t),s=i.length,u=0;s>u;)n.f(e,r=i[u++],t[r]);return e}},{"./_an-object":78,"./_descriptors":93,"./_object-dp":119,"./_object-keys":127}],121:[function(e,t,r){var n=e("./_object-pie"),o=e("./_property-desc"),a=e("./_to-iobject"),i=e("./_to-primitive"),s=e("./_has"),u=e("./_ie8-dom-define"),l=Object.getOwnPropertyDescriptor;r.f=e("./_descriptors")?l:function(e,t){if(e=a(e),t=i(t,!0),u)try{return l(e,t)}catch(r){}if(s(e,t))return o(!n.f.call(e,t),e[t])}},{"./_descriptors":93,"./_has":101,"./_ie8-dom-define":104,"./_object-pie":128,"./_property-desc":130,"./_to-iobject":141,"./_to-primitive":144}],122:[function(e,t,r){var n=e("./_to-iobject"),o=e("./_object-gopn").f,a={}.toString,i="object"==typeof window&&window&&Object.getOwnPropertyNames?Object.getOwnPropertyNames(window):[],s=function(e){try{return o(e)}catch(t){return i.slice()}};t.exports.f=function(e){return i&&"[object Window]"==a.call(e)?s(e):o(n(e))}},{"./_object-gopn":123,"./_to-iobject":141}],123:[function(e,t,r){var n=e("./_object-keys-internal"),o=e("./_enum-bug-keys").concat("length","prototype");r.f=Object.getOwnPropertyNames||function(e){return n(e,o)}},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],124:[function(e,t,r){r.f=Object.getOwnPropertySymbols},{}],125:[function(e,t,r){var n=e("./_has"),o=e("./_to-object"),a=e("./_shared-key")("IE_PROTO"),i=Object.prototype;t.exports=Object.getPrototypeOf||function(e){return e=o(e),n(e,a)?e[a]:"function"==typeof e.constructor&&e instanceof e.constructor?e.constructor.prototype:e instanceof Object?i:null}},{"./_has":101,"./_shared-key":136,"./_to-object":143}],126:[function(e,t,r){var n=e("./_has"),o=e("./_to-iobject"),a=e("./_array-includes")(!1),i=e("./_shared-key")("IE_PROTO");t.exports=function(e,t){var r,s=o(e),u=0,l=[];for(r in s)r!=i&&n(s,r)&&l.push(r);for(;t.length>u;)n(s,r=t[u++])&&(~a(l,r)||l.push(r));return l}},{"./_array-includes":80,"./_has":101,"./_shared-key":136,"./_to-iobject":141}],127:[function(e,t,r){var n=e("./_object-keys-internal"),o=e("./_enum-bug-keys");t.exports=Object.keys||function(e){return n(e,o)}},{"./_enum-bug-keys":95,"./_object-keys-internal":126}],128:[function(e,t,r){r.f={}.propertyIsEnumerable},{}],129:[function(e,t,r){var n=e("./_export"),o=e("./_core"),a=e("./_fails");t.exports=function(e,t){var r=(o.Object||{})[e]||Object[e],i={};i[e]=t(r),n(n.S+n.F*a(function(){r(1)}),"Object",i)}},{"./_core":90,"./_export":97,"./_fails":98}],130:[function(e,t,r){t.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},{}],131:[function(e,t,r){var n=e("./_hide");t.exports=function(e,t,r){for(var o in t)r&&e[o]?e[o]=t[o]:n(e,o,t[o]);return e}},{"./_hide":102}],132:[function(e,t,r){t.exports=e("./_hide")},{"./_hide":102}],133:[function(e,t,r){var n=e("./_is-object"),o=e("./_an-object"),a=function(e,t){if(o(e),!n(t)&&null!==t)throw TypeError(t+": can't set as prototype!")};t.exports={set:Object.setPrototypeOf||("__proto__"in{}?function(t,r,n){try{n=e("./_ctx")(Function.call,e("./_object-gopd").f(Object.prototype,"__proto__").set,2),n(t,[]),r=!(t instanceof Array)}catch(o){r=!0}return function(e,t){return a(e,t),r?e.__proto__=t:n(e,t),e}}({},!1):void 0),check:a}},{"./_an-object":78,"./_ctx":91,"./_is-object":108,"./_object-gopd":121}],134:[function(e,t,r){"use strict";var n=e("./_global"),o=e("./_core"),a=e("./_object-dp"),i=e("./_descriptors"),s=e("./_wks")("species");t.exports=function(e){var t="function"==typeof o[e]?o[e]:n[e];i&&t&&!t[s]&&a.f(t,s,{configurable:!0,get:function(){return this}})}},{"./_core":90,"./_descriptors":93,"./_global":100,"./_object-dp":119,"./_wks":148}],135:[function(e,t,r){var n=e("./_object-dp").f,o=e("./_has"),a=e("./_wks")("toStringTag");t.exports=function(e,t,r){e&&!o(e=r?e:e.prototype,a)&&n(e,a,{configurable:!0,value:t})}},{"./_has":101,"./_object-dp":119,"./_wks":148}],136:[function(e,t,r){var n=e("./_shared")("keys"),o=e("./_uid");t.exports=function(e){return n[e]||(n[e]=o(e))}},{"./_shared":137,"./_uid":145}],137:[function(e,t,r){var n=e("./_global"),o="__core-js_shared__",a=n[o]||(n[o]={});t.exports=function(e){return a[e]||(a[e]={})}},{"./_global":100}],138:[function(e,t,r){var n=e("./_to-integer"),o=e("./_defined");t.exports=function(e){return function(t,r){var a,i,s=String(o(t)),u=n(r),l=s.length;return u<0||u>=l?e?"":void 0:(a=s.charCodeAt(u),a<55296||a>56319||u+1===l||(i=s.charCodeAt(u+1))<56320||i>57343?e?s.charAt(u):a:e?s.slice(u,u+2):(a-55296<<10)+(i-56320)+65536)}}},{"./_defined":92,"./_to-integer":140}],139:[function(e,t,r){var n=e("./_to-integer"),o=Math.max,a=Math.min;t.exports=function(e,t){return e=n(e),e<0?o(e+t,0):a(e,t)}},{"./_to-integer":140}],140:[function(e,t,r){var n=Math.ceil,o=Math.floor;t.exports=function(e){return isNaN(e=+e)?0:(e>0?o:n)(e)}},{}],141:[function(e,t,r){var n=e("./_iobject"),o=e("./_defined");t.exports=function(e){return n(o(e))}},{"./_defined":92,"./_iobject":105}],142:[function(e,t,r){var n=e("./_to-integer"),o=Math.min;t.exports=function(e){return e>0?o(n(e),9007199254740991):0}},{"./_to-integer":140}],143:[function(e,t,r){var n=e("./_defined");t.exports=function(e){return Object(n(e))}},{"./_defined":92}],144:[function(e,t,r){var n=e("./_is-object");t.exports=function(e,t){if(!n(e))return e;var r,o;if(t&&"function"==typeof(r=e.toString)&&!n(o=r.call(e)))return o;if("function"==typeof(r=e.valueOf)&&!n(o=r.call(e)))return o;if(!t&&"function"==typeof(r=e.toString)&&!n(o=r.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},{"./_is-object":108}],145:[function(e,t,r){var n=0,o=Math.random();t.exports=function(e){return"Symbol(".concat(void 0===e?"":e,")_",(++n+o).toString(36))}},{}],146:[function(e,t,r){var n=e("./_global"),o=e("./_core"),a=e("./_library"),i=e("./_wks-ext"),s=e("./_object-dp").f;t.exports=function(e){var t=o.Symbol||(o.Symbol=a?{}:n.Symbol||{});"_"==e.charAt(0)||e in t||s(t,e,{value:i.f(e)})}},{"./_core":90,"./_global":100,"./_library":115,"./_object-dp":119,"./_wks-ext":147}],147:[function(e,t,r){r.f=e("./_wks")},{"./_wks":148}],148:[function(e,t,r){var n=e("./_shared")("wks"),o=e("./_uid"),a=e("./_global").Symbol,i="function"==typeof a,s=t.exports=function(e){return n[e]||(n[e]=i&&a[e]||(i?a:o)("Symbol."+e))};s.store=n},{"./_global":100,"./_shared":137,"./_uid":145}],149:[function(e,t,r){var n=e("./_classof"),o=e("./_wks")("iterator"),a=e("./_iterators");t.exports=e("./_core").getIteratorMethod=function(e){if(void 0!=e)return e[o]||e["@@iterator"]||a[n(e)]}},{"./_classof":84,"./_core":90,"./_iterators":113,"./_wks":148}],150:[function(e,t,r){var n=e("./_an-object"),o=e("./core.get-iterator-method");t.exports=e("./_core").getIterator=function(e){var t=o(e);if("function"!=typeof t)throw TypeError(e+" is not iterable!");return n(t.call(e))}},{"./_an-object":78,"./_core":90,"./core.get-iterator-method":149}],151:[function(e,t,r){"use strict";var n=e("./_add-to-unscopables"),o=e("./_iter-step"),a=e("./_iterators"),i=e("./_to-iobject");t.exports=e("./_iter-define")(Array,"Array",function(e,t){this._t=i(e),this._i=0,this._k=t},function(){var e=this._t,t=this._k,r=this._i++;return!e||r>=e.length?(this._t=void 0,o(1)):"keys"==t?o(0,r):"values"==t?o(0,e[r]):o(0,[r,e[r]])},"values"),a.Arguments=a.Array,n("keys"),n("values"),n("entries")},{"./_add-to-unscopables":76,"./_iter-define":111,"./_iter-step":112,"./_iterators":113,"./_to-iobject":141}],152:[function(e,t,r){"use strict";var n=e("./_collection-strong");t.exports=e("./_collection")("Map",function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}},{get:function(e){var t=n.getEntry(this,e);return t&&t.v},set:function(e,t){return n.def(this,0===e?0:e,t)}},n,!0)},{"./_collection":89,"./_collection-strong":86}],153:[function(e,t,r){var n=e("./_export");n(n.S,"Object",{create:e("./_object-create")})},{"./_export":97,"./_object-create":118}],154:[function(e,t,r){var n=e("./_export");n(n.S+n.F*!e("./_descriptors"),"Object",{defineProperty:e("./_object-dp").f})},{"./_descriptors":93,"./_export":97,"./_object-dp":119}],155:[function(e,t,r){var n=e("./_is-object"),o=e("./_meta").onFreeze;e("./_object-sap")("freeze",function(e){return function(t){return e&&n(t)?e(o(t)):t}})},{"./_is-object":108,"./_meta":116,"./_object-sap":129}],156:[function(e,t,r){var n=e("./_to-iobject"),o=e("./_object-gopd").f;e("./_object-sap")("getOwnPropertyDescriptor",function(){return function(e,t){return o(n(e),t)}})},{"./_object-gopd":121,"./_object-sap":129,"./_to-iobject":141}],157:[function(e,t,r){var n=e("./_to-object"),o=e("./_object-gpo");e("./_object-sap")("getPrototypeOf",function(){return function(e){return o(n(e))}})},{"./_object-gpo":125,"./_object-sap":129,"./_to-object":143}],158:[function(e,t,r){var n=e("./_to-object"),o=e("./_object-keys");e("./_object-sap")("keys",function(){return function(e){return o(n(e))}})},{"./_object-keys":127,"./_object-sap":129,"./_to-object":143}],159:[function(e,t,r){var n=e("./_export");n(n.S,"Object",{setPrototypeOf:e("./_set-proto").set})},{"./_export":97,"./_set-proto":133}],160:[function(e,t,r){},{}],161:[function(e,t,r){"use strict";var n=e("./_string-at")(!0);e("./_iter-define")(String,"String",function(e){this._t=String(e),this._i=0},function(){var e,t=this._t,r=this._i;return r>=t.length?{value:void 0,done:!0}:(e=n(t,r),this._i+=e.length,{value:e,done:!1})})},{"./_iter-define":111,"./_string-at":138}],162:[function(e,t,r){"use strict";var n=e("./_global"),o=e("./_has"),a=e("./_descriptors"),i=e("./_export"),s=e("./_redefine"),u=e("./_meta").KEY,l=e("./_fails"),c=e("./_shared"),f=e("./_set-to-string-tag"),d=e("./_uid"),h=e("./_wks"),p=e("./_wks-ext"),_=e("./_wks-define"),v=e("./_keyof"),y=e("./_enum-keys"),b=e("./_is-array"),g=e("./_an-object"),m=e("./_to-iobject"),C=e("./_to-primitive"),j=e("./_property-desc"),k=e("./_object-create"),O=e("./_object-gopn-ext"),w=e("./_object-gopd"),S=e("./_object-dp"),E=e("./_object-keys"),P=w.f,A=S.f,I=O.f,T=n.Symbol,N=n.JSON,R=N&&N.stringify,M="prototype",x=h("_hidden"),D=h("toPrimitive"),L={}.propertyIsEnumerable,U=c("symbol-registry"),F=c("symbols"),K=c("op-symbols"),q=Object[M],J="function"==typeof T,W=n.QObject,Q=!W||!W[M]||!W[M].findChild,B=a&&l(function(){return 7!=k(A({},"a",{get:function(){return A(this,"a",{value:7}).a}})).a})?function(e,t,r){var n=P(q,t);n&&delete q[t],A(e,t,r),n&&e!==q&&A(q,t,n)}:A,V=function(e){var t=F[e]=k(T[M]);return t._k=e,t},G=J&&"symbol"==typeof T.iterator?function(e){return"symbol"==typeof e}:function(e){return e instanceof T},z=function(e,t,r){return e===q&&z(K,t,r),g(e),t=C(t,!0),g(r),o(F,t)?(r.enumerable?(o(e,x)&&e[x][t]&&(e[x][t]=!1),r=k(r,{enumerable:j(0,!1)})):(o(e,x)||A(e,x,j(1,{})),e[x][t]=!0),B(e,t,r)):A(e,t,r)},Y=function(e,t){g(e);for(var r,n=y(t=m(t)),o=0,a=n.length;a>o;)z(e,r=n[o++],t[r]);return e},H=function(e,t){return void 0===t?k(e):Y(k(e),t); -},$=function(e){var t=L.call(this,e=C(e,!0));return!(this===q&&o(F,e)&&!o(K,e))&&(!(t||!o(this,e)||!o(F,e)||o(this,x)&&this[x][e])||t)},X=function(e,t){if(e=m(e),t=C(t,!0),e!==q||!o(F,t)||o(K,t)){var r=P(e,t);return!r||!o(F,t)||o(e,x)&&e[x][t]||(r.enumerable=!0),r}},Z=function(e){for(var t,r=I(m(e)),n=[],a=0;r.length>a;)o(F,t=r[a++])||t==x||t==u||n.push(t);return n},ee=function(e){for(var t,r=e===q,n=I(r?K:m(e)),a=[],i=0;n.length>i;)!o(F,t=n[i++])||r&&!o(q,t)||a.push(F[t]);return a};J||(T=function(){if(this instanceof T)throw TypeError("Symbol is not a constructor!");var e=d(arguments.length>0?arguments[0]:void 0),t=function(r){this===q&&t.call(K,r),o(this,x)&&o(this[x],e)&&(this[x][e]=!1),B(this,e,j(1,r))};return a&&Q&&B(q,e,{configurable:!0,set:t}),V(e)},s(T[M],"toString",function(){return this._k}),w.f=X,S.f=z,e("./_object-gopn").f=O.f=Z,e("./_object-pie").f=$,e("./_object-gops").f=ee,a&&!e("./_library")&&s(q,"propertyIsEnumerable",$,!0),p.f=function(e){return V(h(e))}),i(i.G+i.W+i.F*!J,{Symbol:T});for(var te="hasInstance,isConcatSpreadable,iterator,match,replace,search,species,split,toPrimitive,toStringTag,unscopables".split(","),re=0;te.length>re;)h(te[re++]);for(var te=E(h.store),re=0;te.length>re;)_(te[re++]);i(i.S+i.F*!J,"Symbol",{"for":function(e){return o(U,e+="")?U[e]:U[e]=T(e)},keyFor:function(e){if(G(e))return v(U,e);throw TypeError(e+" is not a symbol!")},useSetter:function(){Q=!0},useSimple:function(){Q=!1}}),i(i.S+i.F*!J,"Object",{create:H,defineProperty:z,defineProperties:Y,getOwnPropertyDescriptor:X,getOwnPropertyNames:Z,getOwnPropertySymbols:ee}),N&&i(i.S+i.F*(!J||l(function(){var e=T();return"[null]"!=R([e])||"{}"!=R({a:e})||"{}"!=R(Object(e))})),"JSON",{stringify:function(e){if(void 0!==e&&!G(e)){for(var t,r,n=[e],o=1;arguments.length>o;)n.push(arguments[o++]);return t=n[1],"function"==typeof t&&(r=t),!r&&b(t)||(t=function(e,t){if(r&&(t=r.call(this,e,t)),!G(t))return t}),n[1]=t,R.apply(N,n)}}}),T[M][D]||e("./_hide")(T[M],D,T[M].valueOf),f(T,"Symbol"),f(Math,"Math",!0),f(n.JSON,"JSON",!0)},{"./_an-object":78,"./_descriptors":93,"./_enum-keys":96,"./_export":97,"./_fails":98,"./_global":100,"./_has":101,"./_hide":102,"./_is-array":107,"./_keyof":114,"./_library":115,"./_meta":116,"./_object-create":118,"./_object-dp":119,"./_object-gopd":121,"./_object-gopn":123,"./_object-gopn-ext":122,"./_object-gops":124,"./_object-keys":127,"./_object-pie":128,"./_property-desc":130,"./_redefine":132,"./_set-to-string-tag":135,"./_shared":137,"./_to-iobject":141,"./_to-primitive":144,"./_uid":145,"./_wks":148,"./_wks-define":146,"./_wks-ext":147}],163:[function(e,t,r){"use strict";var n,o=e("./_array-methods")(0),a=e("./_redefine"),i=e("./_meta"),s=e("./_object-assign"),u=e("./_collection-weak"),l=e("./_is-object"),c=i.getWeak,f=Object.isExtensible,d=u.ufstore,h={},p=function(e){return function(){return e(this,arguments.length>0?arguments[0]:void 0)}},_={get:function(e){if(l(e)){var t=c(e);return t===!0?d(this).get(e):t?t[this._i]:void 0}},set:function(e,t){return u.def(this,e,t)}},v=t.exports=e("./_collection")("WeakMap",p,_,u,!0,!0);7!=(new v).set((Object.freeze||Object)(h),7).get(h)&&(n=u.getConstructor(p),s(n.prototype,_),i.NEED=!0,o(["delete","has","get","set"],function(e){var t=v.prototype,r=t[e];a(t,e,function(t,o){if(l(t)&&!f(t)){this._f||(this._f=new n);var a=this._f[e](t,o);return"set"==e?this:a}return r.call(this,t,o)})}))},{"./_array-methods":81,"./_collection":89,"./_collection-weak":88,"./_is-object":108,"./_meta":116,"./_object-assign":117,"./_redefine":132}],164:[function(e,t,r){var n=e("./_export");n(n.P+n.R,"Map",{toJSON:e("./_collection-to-json")("Map")})},{"./_collection-to-json":87,"./_export":97}],165:[function(e,t,r){e("./_wks-define")("asyncIterator")},{"./_wks-define":146}],166:[function(e,t,r){e("./_wks-define")("observable")},{"./_wks-define":146}],167:[function(e,t,r){e("./es6.array.iterator");for(var n=e("./_global"),o=e("./_hide"),a=e("./_iterators"),i=e("./_wks")("toStringTag"),s=["NodeList","DOMTokenList","MediaList","StyleSheetList","CSSRuleList"],u=0;u<5;u++){var l=s[u],c=n[l],f=c&&c.prototype;f&&!f[i]&&o(f,i,l),a[l]=a.Array}},{"./_global":100,"./_hide":102,"./_iterators":113,"./_wks":148,"./es6.array.iterator":151}],168:[function(e,t,r){arguments[4][160][0].apply(r,arguments)},{dup:160}],169:[function(e,t,r){function n(){this._events=this._events||{},this._maxListeners=this._maxListeners||void 0}function o(e){return"function"==typeof e}function a(e){return"number"==typeof e}function i(e){return"object"==typeof e&&null!==e}function s(e){return void 0===e}t.exports=n,n.EventEmitter=n,n.prototype._events=void 0,n.prototype._maxListeners=void 0,n.defaultMaxListeners=10,n.prototype.setMaxListeners=function(e){if(!a(e)||e<0||isNaN(e))throw TypeError("n must be a positive number");return this._maxListeners=e,this},n.prototype.emit=function(e){var t,r,n,a,u,l;if(this._events||(this._events={}),"error"===e&&(!this._events.error||i(this._events.error)&&!this._events.error.length)){if(t=arguments[1],t instanceof Error)throw t;throw TypeError('Uncaught, unspecified "error" event.')}if(r=this._events[e],s(r))return!1;if(o(r))switch(arguments.length){case 1:r.call(this);break;case 2:r.call(this,arguments[1]);break;case 3:r.call(this,arguments[1],arguments[2]);break;default:for(n=arguments.length,a=new Array(n-1),u=1;u0&&this._events[e].length>r&&(this._events[e].warned=!0,console.error("(node) warning: possible EventEmitter memory leak detected. %d listeners added. Use emitter.setMaxListeners() to increase limit.",this._events[e].length),"function"==typeof console.trace&&console.trace())}return this},n.prototype.on=n.prototype.addListener,n.prototype.once=function(e,t){function r(){this.removeListener(e,r),n||(n=!0,t.apply(this,arguments))}if(!o(t))throw TypeError("listener must be a function");var n=!1;return r.listener=t,this.on(e,r),this},n.prototype.removeListener=function(e,t){var r,n,a,s;if(!o(t))throw TypeError("listener must be a function");if(!this._events||!this._events[e])return this;if(r=this._events[e],a=r.length,n=-1,r===t||o(r.listener)&&r.listener===t)delete this._events[e],this._events.removeListener&&this.emit("removeListener",e,t);else if(i(r)){for(s=a;s-- >0;)if(r[s]===t||r[s].listener&&r[s].listener===t){n=s;break}if(n<0)return this;1===r.length?(r.length=0,delete this._events[e]):r.splice(n,1),this._events.removeListener&&this.emit("removeListener",e,t)}return this},n.prototype.removeAllListeners=function(e){var t,r;if(!this._events)return this;if(!this._events.removeListener)return 0===arguments.length?this._events={}:this._events[e]&&delete this._events[e],this;if(0===arguments.length){for(t in this._events)"removeListener"!==t&&this.removeAllListeners(t);return this.removeAllListeners("removeListener"),this._events={},this}if(r=this._events[e],o(r))this.removeListener(e,r);else for(;r.length;)this.removeListener(e,r[r.length-1]);return delete this._events[e],this},n.prototype.listeners=function(e){var t;return t=this._events&&this._events[e]?o(this._events[e])?[this._events[e]]:this._events[e].slice():[]},n.listenerCount=function(e,t){var r;return r=e._events&&e._events[t]?o(e._events[t])?1:e._events[t].length:0}},{}]},{},[10])(10)}); \ No newline at end of file diff --git a/lib/browser/Analytics.js b/lib/browser/Analytics.js deleted file mode 100644 index e5bddf088..000000000 --- a/lib/browser/Analytics.js +++ /dev/null @@ -1,89 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.track = track; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Parse.Analytics provides an interface to Parse's logging and analytics - * backend. - * - * @class Parse.Analytics - * @static - */ - -/** - * Tracks the occurrence of a custom event with additional dimensions. - * Parse will store a data point at the time of invocation with the given - * event name. - * - * Dimensions will allow segmentation of the occurrences of this custom - * event. Keys and values should be {@code String}s, and will throw - * otherwise. - * - * To track a user signup along with additional metadata, consider the - * following: - *
                      - * var dimensions = {
                      - *  gender: 'm',
                      - *  source: 'web',
                      - *  dayType: 'weekend'
                      - * };
                      - * Parse.Analytics.track('signup', dimensions);
                      - * 
                      - * - * There is a default limit of 8 dimensions per event tracked. - * - * @method track - * @param {String} name The name of the custom event to report to Parse as - * having happened. - * @param {Object} dimensions The dictionary of information by which to - * segment this event. - * @param {Object} options A Backbone-style callback object. - * @return {Parse.Promise} A promise that is resolved when the round-trip - * to the server completes. - */ -function track(name, dimensions, options) { - name = name || ''; - name = name.replace(/^\s*/, ''); - name = name.replace(/\s*$/, ''); - if (name.length === 0) { - throw new TypeError('A name for the custom event must be provided'); - } - - for (var key in dimensions) { - if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { - throw new TypeError('track() dimensions expects keys and values of type "string".'); - } - } - - options = options || {}; - return _CoreManager2.default.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var DefaultController = { - track: function (name, dimensions) { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); - } -}; - -_CoreManager2.default.setAnalyticsController(DefaultController); \ No newline at end of file diff --git a/lib/browser/Cloud.js b/lib/browser/Cloud.js deleted file mode 100644 index 72c333750..000000000 --- a/lib/browser/Cloud.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.run = run; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains functions for calling and declaring - * cloud functions. - *

                      - * Some functions are only available from Cloud Code. - *

                      - * - * @class Parse.Cloud - * @static - */ - -/** - * Makes a call to a cloud function. - * @method run - * @param {String} name The function name. - * @param {Object} data The parameters to send to the cloud function. - * @param {Object} options A Backbone-style options object - * options.success, if set, should be a function to handle a successful - * call to a cloud function. options.error should be a function that - * handles an error running the cloud function. Both functions are - * optional. Both functions take a single argument. - * @return {Parse.Promise} A promise that will be resolved with the result - * of the function. - */ -function run(name, data, options) { - options = options || {}; - - if (typeof name !== 'string' || name.length === 0) { - throw new TypeError('Cloud function name must be a string.'); - } - - var requestOptions = {}; - if (options.useMasterKey) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.sessionToken) { - requestOptions.sessionToken = options.sessionToken; - } - - return _CoreManager2.default.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var DefaultController = { - run: function (name, data, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - var payload = (0, _encode2.default)(data, true); - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - requestOptions.sessionToken = options.sessionToken; - } - - var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); - - return request.then(function (res) { - var decoded = (0, _decode2.default)(res); - if (decoded && decoded.hasOwnProperty('result')) { - return _ParsePromise2.default.as(decoded.result); - } - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); - })._thenRunCallbacks(options); - } -}; - -_CoreManager2.default.setCloudController(DefaultController); \ No newline at end of file diff --git a/lib/browser/CoreManager.js b/lib/browser/CoreManager.js deleted file mode 100644 index 20d66a5f1..000000000 --- a/lib/browser/CoreManager.js +++ /dev/null @@ -1,161 +0,0 @@ -'use strict'; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var config = { - // Defaults - IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, - REQUEST_ATTEMPT_LIMIT: 5, - SERVER_URL: 'https://api.parse.com/1', - LIVEQUERY_SERVER_URL: null, - VERSION: 'js' + '1.9.2', - APPLICATION_ID: null, - JAVASCRIPT_KEY: null, - MASTER_KEY: null, - USE_MASTER_KEY: false, - PERFORM_USER_REWRITE: true, - FORCE_REVOCABLE_SESSION: false -}; - -function requireMethods(name, methods, controller) { - methods.forEach(function (func) { - if (typeof controller[func] !== 'function') { - throw new Error(name + ' must implement ' + func + '()'); - } - }); -} - -module.exports = { - get: function (key) { - if (config.hasOwnProperty(key)) { - return config[key]; - } - throw new Error('Configuration key not found: ' + key); - }, - - set: function (key, value) { - config[key] = value; - }, - - /* Specialized Controller Setters/Getters */ - - setAnalyticsController: function (controller) { - requireMethods('AnalyticsController', ['track'], controller); - config['AnalyticsController'] = controller; - }, - getAnalyticsController: function () { - return config['AnalyticsController']; - }, - setCloudController: function (controller) { - requireMethods('CloudController', ['run'], controller); - config['CloudController'] = controller; - }, - getCloudController: function () { - return config['CloudController']; - }, - setConfigController: function (controller) { - requireMethods('ConfigController', ['current', 'get'], controller); - config['ConfigController'] = controller; - }, - getConfigController: function () { - return config['ConfigController']; - }, - setFileController: function (controller) { - requireMethods('FileController', ['saveFile', 'saveBase64'], controller); - config['FileController'] = controller; - }, - getFileController: function () { - return config['FileController']; - }, - setInstallationController: function (controller) { - requireMethods('InstallationController', ['currentInstallationId'], controller); - config['InstallationController'] = controller; - }, - getInstallationController: function () { - return config['InstallationController']; - }, - setObjectController: function (controller) { - requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); - config['ObjectController'] = controller; - }, - getObjectController: function () { - return config['ObjectController']; - }, - setObjectStateController: function (controller) { - requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); - - config['ObjectStateController'] = controller; - }, - getObjectStateController: function () { - return config['ObjectStateController']; - }, - setPushController: function (controller) { - requireMethods('PushController', ['send'], controller); - config['PushController'] = controller; - }, - getPushController: function () { - return config['PushController']; - }, - setQueryController: function (controller) { - requireMethods('QueryController', ['find'], controller); - config['QueryController'] = controller; - }, - getQueryController: function () { - return config['QueryController']; - }, - setRESTController: function (controller) { - requireMethods('RESTController', ['request', 'ajax'], controller); - config['RESTController'] = controller; - }, - getRESTController: function () { - return config['RESTController']; - }, - setSessionController: function (controller) { - requireMethods('SessionController', ['getSession'], controller); - config['SessionController'] = controller; - }, - getSessionController: function () { - return config['SessionController']; - }, - setStorageController: function (controller) { - if (controller.async) { - requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); - } else { - requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); - } - config['StorageController'] = controller; - }, - getStorageController: function () { - return config['StorageController']; - }, - setUserController: function (controller) { - requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); - config['UserController'] = controller; - }, - getUserController: function () { - return config['UserController']; - }, - setLiveQueryController: function (controller) { - requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); - config['LiveQueryController'] = controller; - }, - getLiveQueryController: function () { - return config['LiveQueryController']; - }, - setHooksController: function (controller) { - requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); - config['HooksController'] = controller; - }, - getHooksController: function () { - return config['HooksController']; - } -}; \ No newline at end of file diff --git a/lib/browser/EventEmitter.js b/lib/browser/EventEmitter.js deleted file mode 100644 index e9414f0bf..000000000 --- a/lib/browser/EventEmitter.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This is a simple wrapper to unify EventEmitter implementations across platforms. - */ - -module.exports = require('events').EventEmitter; -var EventEmitter; \ No newline at end of file diff --git a/lib/browser/FacebookUtils.js b/lib/browser/FacebookUtils.js deleted file mode 100644 index bb8b7ef51..000000000 --- a/lib/browser/FacebookUtils.js +++ /dev/null @@ -1,243 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _parseDate = require('./parseDate'); - -var _parseDate2 = _interopRequireDefault(_parseDate); - -var _ParseUser = require('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * -weak - */ - -var PUBLIC_KEY = "*"; - -var initialized = false; -var requestedPermissions; -var initOptions; -var provider = { - authenticate: function (options) { - var _this = this; - - if (typeof FB === 'undefined') { - options.error(this, 'Facebook SDK not found.'); - } - FB.login(function (response) { - if (response.authResponse) { - if (options.success) { - options.success(_this, { - id: response.authResponse.userID, - access_token: response.authResponse.accessToken, - expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() - }); - } - } else { - if (options.error) { - options.error(_this, response); - } - } - }, { - scope: requestedPermissions - }); - }, - restoreAuthentication: function (authData) { - if (authData) { - var expiration = (0, _parseDate2.default)(authData.expiration_date); - var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; - - var authResponse = { - userID: authData.id, - accessToken: authData.access_token, - expiresIn: expiresIn - }; - var newOptions = {}; - if (initOptions) { - for (var key in initOptions) { - newOptions[key] = initOptions[key]; - } - } - newOptions.authResponse = authResponse; - - // Suppress checks for login status from the browser. - newOptions.status = false; - - // If the user doesn't match the one known by the FB SDK, log out. - // Most of the time, the users will match -- it's only in cases where - // the FB SDK knows of a different user than the one being restored - // from a Parse User that logged in with username/password. - var existingResponse = FB.getAuthResponse(); - if (existingResponse && existingResponse.userID !== authResponse.userID) { - FB.logout(); - } - - FB.init(newOptions); - } - return true; - }, - getAuthType: function () { - return 'facebook'; - }, - deauthenticate: function () { - this.restoreAuthentication(null); - } -}; - -/** - * Provides a set of utilities for using Parse with Facebook. - * @class Parse.FacebookUtils - * @static - */ -var FacebookUtils = { - /** - * Initializes Parse Facebook integration. Call this function after you - * have loaded the Facebook Javascript SDK with the same parameters - * as you would pass to - * - * FB.init(). Parse.FacebookUtils will invoke FB.init() for you - * with these arguments. - * - * @method init - * @param {Object} options Facebook options argument as described here: - * - * FB.init(). The status flag will be coerced to 'false' because it - * interferes with Parse Facebook integration. Call FB.getLoginStatus() - * explicitly if this behavior is required by your application. - */ - init: function (options) { - if (typeof FB === 'undefined') { - throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); - } - initOptions = {}; - if (options) { - for (var key in options) { - initOptions[key] = options[key]; - } - } - if (initOptions.status && typeof console !== 'undefined') { - var warn = console.warn || console.log || function () {}; - warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); - } - initOptions.status = false; - FB.init(initOptions); - _ParseUser2.default._registerAuthenticationProvider(provider); - initialized = true; - }, - - /** - * Gets whether the user has their account linked to Facebook. - * - * @method isLinked - * @param {Parse.User} user User to check for a facebook link. - * The user must be logged in on this device. - * @return {Boolean} true if the user has their account - * linked to Facebook. - */ - isLinked: function (user) { - return user._isLinked('facebook'); - }, - - /** - * Logs in a user using Facebook. This method delegates to the Facebook - * SDK to authenticate the user, and then automatically logs in (or - * creates, in the case where it is a new user) a Parse.User. - * - * @method logIn - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - logIn: function (permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling logIn.'); - } - requestedPermissions = permissions; - return _ParseUser2.default._logInWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return _ParseUser2.default._logInWith('facebook', newOptions); - } - }, - - /** - * Links Facebook to an existing PFUser. This method delegates to the - * Facebook SDK to authenticate the user, and then automatically links - * the account to the Parse.User. - * - * @method link - * @param {Parse.User} user User to link to Facebook. This must be the - * current user. - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - link: function (user, permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling link.'); - } - requestedPermissions = permissions; - return user._linkWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return user._linkWith('facebook', newOptions); - } - }, - - /** - * Unlinks the Parse.User from a Facebook account. - * - * @method unlink - * @param {Parse.User} user User to unlink from Facebook. This must be the - * current user. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - unlink: function (user, options) { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling unlink.'); - } - return user._unlinkFrom('facebook', options); - } -}; - -exports.default = FacebookUtils; \ No newline at end of file diff --git a/lib/browser/InstallationController.js b/lib/browser/InstallationController.js deleted file mode 100644 index 7b01e3cad..000000000 --- a/lib/browser/InstallationController.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var iidCache = null; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function hexOctet() { - return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); -} - -function generateId() { - return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); -} - -var InstallationController = { - currentInstallationId: function () { - if (typeof iidCache === 'string') { - return _ParsePromise2.default.as(iidCache); - } - var path = _Storage2.default.generatePath('installationId'); - return _Storage2.default.getItemAsync(path).then(function (iid) { - if (!iid) { - iid = generateId(); - return _Storage2.default.setItemAsync(path, iid).then(function () { - iidCache = iid; - return iid; - }); - } - iidCache = iid; - return iid; - }); - }, - _clearCache: function () { - iidCache = null; - }, - _setInstallationIdCache: function (iid) { - iidCache = iid; - } -}; - -module.exports = InstallationController; \ No newline at end of file diff --git a/lib/browser/LiveQueryClient.js b/lib/browser/LiveQueryClient.js deleted file mode 100644 index bc9603a62..000000000 --- a/lib/browser/LiveQueryClient.js +++ /dev/null @@ -1,595 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getIterator2 = require('babel-runtime/core-js/get-iterator'); - -var _getIterator3 = _interopRequireDefault(_getIterator2); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _map = require('babel-runtime/core-js/map'); - -var _map2 = _interopRequireDefault(_map); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _EventEmitter2 = require('./EventEmitter'); - -var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _LiveQuerySubscription = require('./LiveQuerySubscription'); - -var _LiveQuerySubscription2 = _interopRequireDefault(_LiveQuerySubscription); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -// The LiveQuery client inner state -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -var CLIENT_STATE = { - INITIALIZED: 'initialized', - CONNECTING: 'connecting', - CONNECTED: 'connected', - CLOSED: 'closed', - RECONNECTING: 'reconnecting', - DISCONNECTED: 'disconnected' -}; - -// The event type the LiveQuery client should sent to server -var OP_TYPES = { - CONNECT: 'connect', - SUBSCRIBE: 'subscribe', - UNSUBSCRIBE: 'unsubscribe', - ERROR: 'error' -}; - -// The event we get back from LiveQuery server -var OP_EVENTS = { - CONNECTED: 'connected', - SUBSCRIBED: 'subscribed', - UNSUBSCRIBED: 'unsubscribed', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -// The event the LiveQuery client should emit -var CLIENT_EMMITER_TYPES = { - CLOSE: 'close', - ERROR: 'error', - OPEN: 'open' -}; - -// The event the LiveQuery subscription should emit -var SUBSCRIPTION_EMMITER_TYPES = { - OPEN: 'open', - CLOSE: 'close', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -var generateInterval = function (k) { - return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; -}; - -/** - * Creates a new LiveQueryClient. - * Extends events.EventEmitter - * cloud functions. - * - * A wrapper of a standard WebSocket client. We add several useful methods to - * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. - * - * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries - * to connect to the LiveQuery server - * - * @class Parse.LiveQueryClient - * @constructor - * @param {Object} options - * @param {string} options.applicationId - applicationId of your Parse app - * @param {string} options.serverURL - the URL of your LiveQuery server - * @param {string} options.javascriptKey (optional) - * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) - * @param {string} options.sessionToken (optional) - * - * - * We expose three events to help you monitor the status of the LiveQueryClient. - * - *
                      - * let Parse = require('parse/node');
                      - * let LiveQueryClient = Parse.LiveQueryClient;
                      - * let client = new LiveQueryClient({
                      - *   applicationId: '',
                      - *   serverURL: '',
                      - *   javascriptKey: '',
                      - *   masterKey: ''
                      - *  });
                      - * 
                      - * - * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - *
                      - * client.on('open', () => {
                      - * 
                      - * });
                      - * - * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - *
                      - * client.on('close', () => {
                      - * 
                      - * });
                      - * - * Error - When some network error or LiveQuery server error happens, you'll get this event. - *
                      - * client.on('error', (error) => {
                      - * 
                      - * });
                      - * - * - */ - -var LiveQueryClient = function (_EventEmitter) { - (0, _inherits3.default)(LiveQueryClient, _EventEmitter); - - function LiveQueryClient(_ref) { - var applicationId = _ref.applicationId, - serverURL = _ref.serverURL, - javascriptKey = _ref.javascriptKey, - masterKey = _ref.masterKey, - sessionToken = _ref.sessionToken; - (0, _classCallCheck3.default)(this, LiveQueryClient); - - var _this = (0, _possibleConstructorReturn3.default)(this, (LiveQueryClient.__proto__ || (0, _getPrototypeOf2.default)(LiveQueryClient)).call(this)); - - if (!serverURL || serverURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - _this.reconnectHandle = null; - _this.attempts = 1;; - _this.id = 0; - _this.requestId = 1; - _this.serverURL = serverURL; - _this.applicationId = applicationId; - _this.javascriptKey = javascriptKey; - _this.masterKey = masterKey; - _this.sessionToken = sessionToken; - _this.connectPromise = new _ParsePromise2.default(); - _this.subscriptions = new _map2.default(); - _this.state = CLIENT_STATE.INITIALIZED; - return _this; - } - - (0, _createClass3.default)(LiveQueryClient, [{ - key: 'shouldOpen', - value: function () { - return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; - } - - /** - * Subscribes to a ParseQuery - * - * If you provide the sessionToken, when the LiveQuery server gets ParseObject's - * updates from parse server, it'll try to check whether the sessionToken fulfills - * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose - * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol - * here for more details. The subscription you get is the same subscription you get - * from our Standard API. - * - * @method subscribe - * @param {Object} query - the ParseQuery you want to subscribe to - * @param {string} sessionToken (optional) - * @return {Object} subscription - */ - - }, { - key: 'subscribe', - value: function (query, sessionToken) { - var _this2 = this; - - if (!query) { - return; - } - var where = query.toJSON().where; - var className = query.className; - var subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: this.requestId, - query: { - className: className, - where: where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - var subscription = new _LiveQuerySubscription2.default(this.requestId, query, sessionToken); - this.subscriptions.set(this.requestId, subscription); - this.requestId += 1; - this.connectPromise.then(function () { - _this2.socket.send((0, _stringify2.default)(subscribeRequest)); - }); - - // adding listener so process does not crash - // best practice is for developer to register their own listener - subscription.on('error', function () {}); - - return subscription; - } - - /** - * After calling unsubscribe you'll stop receiving events from the subscription object. - * - * @method unsubscribe - * @param {Object} subscription - subscription you would like to unsubscribe from. - */ - - }, { - key: 'unsubscribe', - value: function (subscription) { - var _this3 = this; - - if (!subscription) { - return; - } - - this.subscriptions.delete(subscription.id); - var unsubscribeRequest = { - op: OP_TYPES.UNSUBSCRIBE, - requestId: subscription.id - }; - this.connectPromise.then(function () { - _this3.socket.send((0, _stringify2.default)(unsubscribeRequest)); - }); - } - - /** - * After open is called, the LiveQueryClient will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ - - }, { - key: 'open', - value: function () { - var _this4 = this; - - var WebSocketImplementation = this._getWebSocketImplementation(); - if (!WebSocketImplementation) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); - return; - } - - if (this.state !== CLIENT_STATE.RECONNECTING) { - this.state = CLIENT_STATE.CONNECTING; - } - - // Get WebSocket implementation - this.socket = new WebSocketImplementation(this.serverURL); - - // Bind WebSocket callbacks - this.socket.onopen = function () { - _this4._handleWebSocketOpen(); - }; - - this.socket.onmessage = function (event) { - _this4._handleWebSocketMessage(event); - }; - - this.socket.onclose = function () { - _this4._handleWebSocketClose(); - }; - - this.socket.onerror = function (error) { - _this4._handleWebSocketError(error); - }; - } - }, { - key: 'resubscribe', - value: function () { - var _this5 = this; - - this.subscriptions.forEach(function (subscription, requestId) { - var query = subscription.query; - var where = query.toJSON().where; - var className = query.className; - var sessionToken = subscription.sessionToken; - var subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: requestId, - query: { - className: className, - where: where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - _this5.connectPromise.then(function () { - _this5.socket.send((0, _stringify2.default)(subscribeRequest)); - }); - }); - } - - /** - * This method will close the WebSocket connection to this LiveQueryClient, - * cancel the auto reconnect and unsubscribe all subscriptions based on it. - * - * @method close - */ - - }, { - key: 'close', - value: function () { - if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.DISCONNECTED; - this.socket.close(); - // Notify each subscription about the close - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = (0, _getIterator3.default)(this.subscriptions.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var subscription = _step.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - this._handleReset(); - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - } - }, { - key: '_getWebSocketImplementation', - value: function () { - return typeof WebSocket === 'function' || (typeof WebSocket === 'undefined' ? 'undefined' : (0, _typeof3.default)(WebSocket)) === 'object' ? WebSocket : null; - } - - // ensure we start with valid state if connect is called again after close - - }, { - key: '_handleReset', - value: function () { - this.attempts = 1;; - this.id = 0; - this.requestId = 1; - this.connectPromise = new _ParsePromise2.default(); - this.subscriptions = new _map2.default(); - } - }, { - key: '_handleWebSocketOpen', - value: function () { - this.attempts = 1; - var connectRequest = { - op: OP_TYPES.CONNECT, - applicationId: this.applicationId, - javascriptKey: this.javascriptKey, - masterKey: this.masterKey, - sessionToken: this.sessionToken - }; - this.socket.send((0, _stringify2.default)(connectRequest)); - } - }, { - key: '_handleWebSocketMessage', - value: function (event) { - var data = event.data; - if (typeof data === 'string') { - data = JSON.parse(data); - } - var subscription = null; - if (data.requestId) { - subscription = this.subscriptions.get(data.requestId); - } - switch (data.op) { - case OP_EVENTS.CONNECTED: - if (this.state === CLIENT_STATE.RECONNECTING) { - this.resubscribe(); - } - this.emit(CLIENT_EMMITER_TYPES.OPEN); - this.id = data.clientId; - this.connectPromise.resolve(); - this.state = CLIENT_STATE.CONNECTED; - break; - case OP_EVENTS.SUBSCRIBED: - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); - } - break; - case OP_EVENTS.ERROR: - if (data.requestId) { - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); - } - } else { - this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); - } - break; - case OP_EVENTS.UNSUBSCRIBED: - // We have already deleted subscription in unsubscribe(), do nothing here - break; - default: - // create, update, enter, leave, delete cases - var className = data.object.className; - // Delete the extrea __type and className fields during transfer to full JSON - delete data.object.__type; - delete data.object.className; - var parseObject = new _ParseObject2.default(className); - parseObject._finishFetch(data.object); - if (!subscription) { - break; - } - subscription.emit(data.op, parseObject); - } - } - }, { - key: '_handleWebSocketClose', - value: function () { - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.CLOSED; - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - // Notify each subscription about the close - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = (0, _getIterator3.default)(this.subscriptions.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var subscription = _step2.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - this._handleReconnect(); - } - }, { - key: '_handleWebSocketError', - value: function (error) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, error); - var _iteratorNormalCompletion3 = true; - var _didIteratorError3 = false; - var _iteratorError3 = undefined; - - try { - for (var _iterator3 = (0, _getIterator3.default)(this.subscriptions.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { - var subscription = _step3.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); - } - } catch (err) { - _didIteratorError3 = true; - _iteratorError3 = err; - } finally { - try { - if (!_iteratorNormalCompletion3 && _iterator3.return) { - _iterator3.return(); - } - } finally { - if (_didIteratorError3) { - throw _iteratorError3; - } - } - } - - this._handleReconnect(); - } - }, { - key: '_handleReconnect', - value: function () { - var _this6 = this; - - // if closed or currently reconnecting we stop attempting to reconnect - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - - this.state = CLIENT_STATE.RECONNECTING; - var time = generateInterval(this.attempts); - - // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. - // we're unable to distinguish different between close/error when we're unable to reconnect therefore - // we try to reonnect in both cases - // server side ws and browser WebSocket behave differently in when close/error get triggered - - if (this.reconnectHandle) { - clearTimeout(this.reconnectHandle); - } - - this.reconnectHandle = setTimeout(function () { - _this6.attempts++; - _this6.connectPromise = new _ParsePromise2.default(); - _this6.open(); - }.bind(this), time); - } - }]); - return LiveQueryClient; -}(_EventEmitter3.default); - -exports.default = LiveQueryClient; \ No newline at end of file diff --git a/lib/browser/LiveQuerySubscription.js b/lib/browser/LiveQuerySubscription.js deleted file mode 100644 index 4078b65d5..000000000 --- a/lib/browser/LiveQuerySubscription.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _EventEmitter2 = require('./EventEmitter'); - -var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new LiveQuery Subscription. - * Extends events.EventEmitter - * cloud functions. - * - * @constructor - * @param {string} id - subscription id - * @param {string} query - query to subscribe to - * @param {string} sessionToken - optional session token - * - *

                      Open Event - When you call query.subscribe(), we send a subscribe request to - * the LiveQuery server, when we get the confirmation from the LiveQuery server, - * this event will be emitted. When the client loses WebSocket connection to the - * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we - * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, - * you'll also get this event. - * - *

                      - * subscription.on('open', () => {
                      - * 
                      - * });

                      - * - *

                      Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, - * you'll get this event. The object is the ParseObject which is created. - * - *

                      - * subscription.on('create', (object) => {
                      - * 
                      - * });

                      - * - *

                      Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe - * is updated (The ParseObject fulfills the ParseQuery before and after changes), - * you'll get this event. The object is the ParseObject which is updated. - * Its content is the latest value of the ParseObject. - * - *

                      - * subscription.on('update', (object) => {
                      - * 
                      - * });

                      - * - *

                      Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery - * but its new value fulfills the ParseQuery, you'll get this event. The object is the - * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                      - * subscription.on('enter', (object) => {
                      - * 
                      - * });

                      - * - * - *

                      Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value - * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject - * which leaves the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                      - * subscription.on('leave', (object) => {
                      - * 
                      - * });

                      - * - * - *

                      Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll - * get this event. The object is the ParseObject which is deleted. - * - *

                      - * subscription.on('delete', (object) => {
                      - * 
                      - * });

                      - * - * - *

                      Close Event - When the client loses the WebSocket connection to the LiveQuery - * server and we stop receiving events, you'll get this event. - * - *

                      - * subscription.on('close', () => {
                      - * 
                      - * });

                      - * - * - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -var Subscription = function (_EventEmitter) { - (0, _inherits3.default)(Subscription, _EventEmitter); - - function Subscription(id, query, sessionToken) { - (0, _classCallCheck3.default)(this, Subscription); - - var _this2 = (0, _possibleConstructorReturn3.default)(this, (Subscription.__proto__ || (0, _getPrototypeOf2.default)(Subscription)).call(this)); - - _this2.id = id; - _this2.query = query; - _this2.sessionToken = sessionToken; - return _this2; - } - - /** - * @method unsubscribe - */ - - (0, _createClass3.default)(Subscription, [{ - key: 'unsubscribe', - value: function () { - var _this3 = this; - - var _this = this; - _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient().then(function (liveQueryClient) { - liveQueryClient.unsubscribe(_this); - _this.emit('close'); - _this3.resolve(); - }); - } - }]); - return Subscription; -}(_EventEmitter3.default); - -exports.default = Subscription; \ No newline at end of file diff --git a/lib/browser/ObjectStateMutations.js b/lib/browser/ObjectStateMutations.js deleted file mode 100644 index b476a0e2f..000000000 --- a/lib/browser/ObjectStateMutations.js +++ /dev/null @@ -1,165 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.defaultState = defaultState; -exports.setServerData = setServerData; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _TaskQueue = require('./TaskQueue'); - -var _TaskQueue2 = _interopRequireDefault(_TaskQueue); - -var _ParseOp = require('./ParseOp'); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function defaultState() { - return { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new _TaskQueue2.default(), - existed: false - }; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function setServerData(serverData, attributes) { - for (var _attr in attributes) { - if (typeof attributes[_attr] !== 'undefined') { - serverData[_attr] = attributes[_attr]; - } else { - delete serverData[_attr]; - } - } -} - -function setPendingOp(pendingOps, attr, op) { - var last = pendingOps.length - 1; - if (op) { - pendingOps[last][attr] = op; - } else { - delete pendingOps[last][attr]; - } -} - -function pushPendingState(pendingOps) { - pendingOps.push({}); -} - -function popPendingState(pendingOps) { - var first = pendingOps.shift(); - if (!pendingOps.length) { - pendingOps[0] = {}; - } - return first; -} - -function mergeFirstPendingState(pendingOps) { - var first = popPendingState(pendingOps); - var next = pendingOps[0]; - for (var _attr2 in first) { - if (next[_attr2] && first[_attr2]) { - var merged = next[_attr2].mergeWith(first[_attr2]); - if (merged) { - next[_attr2] = merged; - } - } else { - next[_attr2] = first[_attr2]; - } - } -} - -function estimateAttribute(serverData, pendingOps, className, id, attr) { - var value = serverData[attr]; - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i][attr]) { - if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { - if (id) { - value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); - } - } else { - value = pendingOps[i][attr].applyTo(value); - } - } - } - return value; -} - -function estimateAttributes(serverData, pendingOps, className, id) { - var data = {}; - var attr = void 0; - for (attr in serverData) { - data[attr] = serverData[attr]; - } - for (var i = 0; i < pendingOps.length; i++) { - for (attr in pendingOps[i]) { - if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { - if (id) { - data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); - } - } else { - data[attr] = pendingOps[i][attr].applyTo(data[attr]); - } - } - } - return data; -} - -function commitServerChanges(serverData, objectCache, changes) { - for (var _attr3 in changes) { - var val = changes[_attr3]; - serverData[_attr3] = val; - if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof _ParseObject2.default) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { - var json = (0, _encode2.default)(val, false, true); - objectCache[_attr3] = (0, _stringify2.default)(json); - } - } -} \ No newline at end of file diff --git a/lib/browser/Parse.js b/lib/browser/Parse.js deleted file mode 100644 index 2499dc786..000000000 --- a/lib/browser/Parse.js +++ /dev/null @@ -1,186 +0,0 @@ -'use strict'; - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _InstallationController = require('./InstallationController'); - -var _InstallationController2 = _interopRequireDefault(_InstallationController); - -var _ParseOp = require('./ParseOp'); - -var ParseOp = _interopRequireWildcard(_ParseOp); - -var _RESTController = require('./RESTController'); - -var _RESTController2 = _interopRequireDefault(_RESTController); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains all Parse API classes and functions. - * @class Parse - * @static - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var Parse = { - /** - * Call this method first to set up your authentication tokens for Parse. - * You can get your keys from the Data Browser on parse.com. - * @method initialize - * @param {String} applicationId Your Parse Application ID. - * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) - * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) - * @static - */ - initialize: function (applicationId, javaScriptKey) { - if ('browser' === 'browser' && _CoreManager2.default.get('IS_NODE')) { - console.log('It looks like you\'re using the browser version of the SDK in a ' + 'node.js environment. You should require(\'parse/node\') instead.'); - } - Parse._initialize(applicationId, javaScriptKey); - }, - _initialize: function (applicationId, javaScriptKey, masterKey) { - _CoreManager2.default.set('APPLICATION_ID', applicationId); - _CoreManager2.default.set('JAVASCRIPT_KEY', javaScriptKey); - _CoreManager2.default.set('MASTER_KEY', masterKey); - _CoreManager2.default.set('USE_MASTER_KEY', false); - } -}; - -/** These legacy setters may eventually be deprecated **/ -Object.defineProperty(Parse, 'applicationId', { - get: function () { - return _CoreManager2.default.get('APPLICATION_ID'); - }, - set: function (value) { - _CoreManager2.default.set('APPLICATION_ID', value); - } -}); -Object.defineProperty(Parse, 'javaScriptKey', { - get: function () { - return _CoreManager2.default.get('JAVASCRIPT_KEY'); - }, - set: function (value) { - _CoreManager2.default.set('JAVASCRIPT_KEY', value); - } -}); -Object.defineProperty(Parse, 'masterKey', { - get: function () { - return _CoreManager2.default.get('MASTER_KEY'); - }, - set: function (value) { - _CoreManager2.default.set('MASTER_KEY', value); - } -}); -Object.defineProperty(Parse, 'serverURL', { - get: function () { - return _CoreManager2.default.get('SERVER_URL'); - }, - set: function (value) { - _CoreManager2.default.set('SERVER_URL', value); - } -}); -Object.defineProperty(Parse, 'liveQueryServerURL', { - get: function () { - return _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); - }, - set: function (value) { - _CoreManager2.default.set('LIVEQUERY_SERVER_URL', value); - } -}); -/** End setters **/ - -Parse.ACL = require('./ParseACL').default; -Parse.Analytics = require('./Analytics'); -Parse.Cloud = require('./Cloud'); -Parse.CoreManager = require('./CoreManager'); -Parse.Config = require('./ParseConfig').default; -Parse.Error = require('./ParseError').default; -Parse.FacebookUtils = require('./FacebookUtils').default; -Parse.File = require('./ParseFile').default; -Parse.GeoPoint = require('./ParseGeoPoint').default; -Parse.Installation = require('./ParseInstallation').default; -Parse.Object = require('./ParseObject').default; -Parse.Op = { - Set: ParseOp.SetOp, - Unset: ParseOp.UnsetOp, - Increment: ParseOp.IncrementOp, - Add: ParseOp.AddOp, - Remove: ParseOp.RemoveOp, - AddUnique: ParseOp.AddUniqueOp, - Relation: ParseOp.RelationOp -}; -Parse.Promise = require('./ParsePromise').default; -Parse.Push = require('./Push'); -Parse.Query = require('./ParseQuery').default; -Parse.Relation = require('./ParseRelation').default; -Parse.Role = require('./ParseRole').default; -Parse.Session = require('./ParseSession').default; -Parse.Storage = require('./Storage'); -Parse.User = require('./ParseUser').default; -Parse.LiveQuery = require('./ParseLiveQuery').default; -Parse.LiveQueryClient = require('./LiveQueryClient').default; - -Parse._request = function () { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _CoreManager2.default.getRESTController().request.apply(null, args); -}; -Parse._ajax = function () { - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return _CoreManager2.default.getRESTController().ajax.apply(null, args); -}; -// We attempt to match the signatures of the legacy versions of these methods -Parse._decode = function (_, value) { - return (0, _decode2.default)(value); -}; -Parse._encode = function (value, _, disallowObjects) { - return (0, _encode2.default)(value, disallowObjects); -}; -Parse._getInstallationId = function () { - return _CoreManager2.default.getInstallationController().currentInstallationId(); -}; - -_CoreManager2.default.setInstallationController(_InstallationController2.default); -_CoreManager2.default.setRESTController(_RESTController2.default); - -// For legacy requires, of the form `var Parse = require('parse').Parse` -Parse.Parse = Parse; - -module.exports = Parse; \ No newline at end of file diff --git a/lib/browser/ParseACL.js b/lib/browser/ParseACL.js deleted file mode 100644 index 2aa232c18..000000000 --- a/lib/browser/ParseACL.js +++ /dev/null @@ -1,406 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParseRole = require('./ParseRole'); - -var _ParseRole2 = _interopRequireDefault(_ParseRole); - -var _ParseUser = require('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var PUBLIC_KEY = '*'; - -/** - * Creates a new ACL. - * If no argument is given, the ACL has no permissions for anyone. - * If the argument is a Parse.User, the ACL will have read and write - * permission for only that user. - * If the argument is any other JSON object, that object will be interpretted - * as a serialized ACL created with toJSON(). - * @class Parse.ACL - * @constructor - * - *

                      An ACL, or Access Control List can be added to any - * Parse.Object to restrict access to only a subset of users - * of your application.

                      - */ - -var ParseACL = function () { - function ParseACL(arg1) { - (0, _classCallCheck3.default)(this, ParseACL); - - this.permissionsById = {}; - if (arg1 && (typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { - if (arg1 instanceof _ParseUser2.default) { - this.setReadAccess(arg1, true); - this.setWriteAccess(arg1, true); - } else { - for (var userId in arg1) { - var accessList = arg1[userId]; - if (typeof userId !== 'string') { - throw new TypeError('Tried to create an ACL with an invalid user id.'); - } - this.permissionsById[userId] = {}; - for (var permission in accessList) { - var allowed = accessList[permission]; - if (permission !== 'read' && permission !== 'write') { - throw new TypeError('Tried to create an ACL with an invalid permission type.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('Tried to create an ACL with an invalid permission value.'); - } - this.permissionsById[userId][permission] = allowed; - } - } - } - } else if (typeof arg1 === 'function') { - throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); - } - } - - /** - * Returns a JSON-encoded version of the ACL. - * @method toJSON - * @return {Object} - */ - - (0, _createClass3.default)(ParseACL, [{ - key: 'toJSON', - value: function () { - var permissions = {}; - for (var p in this.permissionsById) { - permissions[p] = this.permissionsById[p]; - } - return permissions; - } - - /** - * Returns whether this ACL is equal to another object - * @method equals - * @param other The other object to compare to - * @return {Boolean} - */ - - }, { - key: 'equals', - value: function (other) { - if (!(other instanceof ParseACL)) { - return false; - } - var users = (0, _keys2.default)(this.permissionsById); - var otherUsers = (0, _keys2.default)(other.permissionsById); - if (users.length !== otherUsers.length) { - return false; - } - for (var u in this.permissionsById) { - if (!other.permissionsById[u]) { - return false; - } - if (this.permissionsById[u].read !== other.permissionsById[u].read) { - return false; - } - if (this.permissionsById[u].write !== other.permissionsById[u].write) { - return false; - } - } - return true; - } - }, { - key: '_setAccess', - value: function (accessType, userId, allowed) { - if (userId instanceof _ParseUser2.default) { - userId = userId.id; - } else if (userId instanceof _ParseRole2.default) { - var name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - if (typeof userId !== 'string') { - throw new TypeError('userId must be a string.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('allowed must be either true or false.'); - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - if (!allowed) { - // The user already doesn't have this permission, so no action is needed - return; - } else { - permissions = {}; - this.permissionsById[userId] = permissions; - } - } - - if (allowed) { - this.permissionsById[userId][accessType] = true; - } else { - delete permissions[accessType]; - if ((0, _keys2.default)(permissions).length === 0) { - delete this.permissionsById[userId]; - } - } - } - }, { - key: '_getAccess', - value: function (accessType, userId) { - if (userId instanceof _ParseUser2.default) { - userId = userId.id; - if (!userId) { - throw new Error('Cannot get access for a ParseUser without an ID'); - } - } else if (userId instanceof _ParseRole2.default) { - var name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - return false; - } - return !!permissions[accessType]; - } - - /** - * Sets whether the given user is allowed to read this object. - * @method setReadAccess - * @param userId An instance of Parse.User or its objectId. - * @param {Boolean} allowed Whether that user should have read access. - */ - - }, { - key: 'setReadAccess', - value: function (userId, allowed) { - this._setAccess('read', userId, allowed); - } - - /** - * Get whether the given user id is *explicitly* allowed to read this object. - * Even if this returns false, the user may still be able to access it if - * getPublicReadAccess returns true or a role that the user belongs to has - * write access. - * @method getReadAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - - }, { - key: 'getReadAccess', - value: function (userId) { - return this._getAccess('read', userId); - } - - /** - * Sets whether the given user id is allowed to write this object. - * @method setWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. - * @param {Boolean} allowed Whether that user should have write access. - */ - - }, { - key: 'setWriteAccess', - value: function (userId, allowed) { - this._setAccess('write', userId, allowed); - } - - /** - * Gets whether the given user id is *explicitly* allowed to write this object. - * Even if this returns false, the user may still be able to write it if - * getPublicWriteAccess returns true or a role that the user belongs to has - * write access. - * @method getWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - - }, { - key: 'getWriteAccess', - value: function (userId) { - return this._getAccess('write', userId); - } - - /** - * Sets whether the public is allowed to read this object. - * @method setPublicReadAccess - * @param {Boolean} allowed - */ - - }, { - key: 'setPublicReadAccess', - value: function (allowed) { - this.setReadAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to read this object. - * @method getPublicReadAccess - * @return {Boolean} - */ - - }, { - key: 'getPublicReadAccess', - value: function () { - return this.getReadAccess(PUBLIC_KEY); - } - - /** - * Sets whether the public is allowed to write this object. - * @method setPublicWriteAccess - * @param {Boolean} allowed - */ - - }, { - key: 'setPublicWriteAccess', - value: function (allowed) { - this.setWriteAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to write this object. - * @method getPublicWriteAccess - * @return {Boolean} - */ - - }, { - key: 'getPublicWriteAccess', - value: function () { - return this.getWriteAccess(PUBLIC_KEY); - } - - /** - * Gets whether users belonging to the given role are allowed - * to read this object. Even if this returns false, the role may - * still be able to write it if a parent role has read access. - * - * @method getRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has read access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'getRoleReadAccess', - value: function (role) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getReadAccess('role:' + role); - } - - /** - * Gets whether users belonging to the given role are allowed - * to write this object. Even if this returns false, the role may - * still be able to write it if a parent role has write access. - * - * @method getRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has write access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'getRoleWriteAccess', - value: function (role) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getWriteAccess('role:' + role); - } - - /** - * Sets whether users belonging to the given role are allowed - * to read this object. - * - * @method setRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can read this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'setRoleReadAccess', - value: function (role, allowed) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setReadAccess('role:' + role, allowed); - } - - /** - * Sets whether users belonging to the given role are allowed - * to write this object. - * - * @method setRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can write this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'setRoleWriteAccess', - value: function (role, allowed) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setWriteAccess('role:' + role, allowed); - } - }]); - return ParseACL; -}(); - -exports.default = ParseACL; \ No newline at end of file diff --git a/lib/browser/ParseConfig.js b/lib/browser/ParseConfig.js deleted file mode 100644 index 925e3a864..000000000 --- a/lib/browser/ParseConfig.js +++ /dev/null @@ -1,228 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _escape2 = require('./escape'); - -var _escape3 = _interopRequireDefault(_escape2); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Parse.Config is a local representation of configuration data that - * can be set from the Parse dashboard. - * - * @class Parse.Config - * @constructor - */ - -var ParseConfig = function () { - function ParseConfig() { - (0, _classCallCheck3.default)(this, ParseConfig); - - this.attributes = {}; - this._escapedAttributes = {}; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The name of an attribute. - */ - - (0, _createClass3.default)(ParseConfig, [{ - key: 'get', - value: function (attr) { - return this.attributes[attr]; - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The name of an attribute. - */ - - }, { - key: 'escape', - value: function (attr) { - var html = this._escapedAttributes[attr]; - if (html) { - return html; - } - var val = this.attributes[attr]; - var escaped = ''; - if (val != null) { - escaped = (0, _escape3.default)(val.toString()); - } - this._escapedAttributes[attr] = escaped; - return escaped; - } - - /** - * Retrieves the most recently-fetched configuration object, either from - * memory or from local storage if necessary. - * - * @method current - * @static - * @return {Config} The most recently-fetched Parse.Config if it - * exists, else an empty Parse.Config. - */ - - }], [{ - key: 'current', - value: function () { - var controller = _CoreManager2.default.getConfigController(); - return controller.current(); - } - - /** - * Gets a new configuration object from the server. - * @method get - * @static - * @param {Object} options A Backbone-style options object. - * Valid options are:
                        - *
                      • success: Function to call when the get completes successfully. - *
                      • error: Function to call when the get fails. - *
                      - * @return {Parse.Promise} A promise that is resolved with a newly-created - * configuration object when the get completes. - */ - - }, { - key: 'get', - value: function (options) { - options = options || {}; - - var controller = _CoreManager2.default.getConfigController(); - return controller.get()._thenRunCallbacks(options); - } - }]); - return ParseConfig; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseConfig; - -var currentConfig = null; - -var CURRENT_CONFIG_KEY = 'currentConfig'; - -function decodePayload(data) { - try { - var json = JSON.parse(data); - if (json && (typeof json === 'undefined' ? 'undefined' : (0, _typeof3.default)(json)) === 'object') { - return (0, _decode2.default)(json); - } - } catch (e) { - return null; - } -} - -var DefaultController = { - current: function () { - if (currentConfig) { - return currentConfig; - } - - var config = new ParseConfig(); - var storagePath = _Storage2.default.generatePath(CURRENT_CONFIG_KEY); - var configData; - if (!_Storage2.default.async()) { - configData = _Storage2.default.getItem(storagePath); - - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - } - // Return a promise for async storage controllers - return _Storage2.default.getItemAsync(storagePath).then(function (configData) { - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - }); - }, - get: function () { - var RESTController = _CoreManager2.default.getRESTController(); - - return RESTController.request('GET', 'config', {}, {}).then(function (response) { - if (!response || !response.params) { - var error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Config JSON response invalid.'); - return _ParsePromise2.default.error(error); - } - - var config = new ParseConfig(); - config.attributes = {}; - for (var attr in response.params) { - config.attributes[attr] = (0, _decode2.default)(response.params[attr]); - } - currentConfig = config; - return _Storage2.default.setItemAsync(_Storage2.default.generatePath(CURRENT_CONFIG_KEY), (0, _stringify2.default)(response.params)).then(function () { - return config; - }); - }); - } -}; - -_CoreManager2.default.setConfigController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseError.js b/lib/browser/ParseError.js deleted file mode 100644 index b3bad4512..000000000 --- a/lib/browser/ParseError.js +++ /dev/null @@ -1,507 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/** - * Constructs a new Parse.Error object with the given code and message. - * @class Parse.Error - * @constructor - * @param {Number} code An error code constant from Parse.Error. - * @param {String} message A detailed description of the error. - */ -var ParseError = function ParseError(code, message) { - (0, _classCallCheck3.default)(this, ParseError); - - this.code = code; - this.message = message; -}; - -/** - * Error code indicating some error other than those enumerated here. - * @property OTHER_CAUSE - * @static - * @final - */ - -exports.default = ParseError; -ParseError.OTHER_CAUSE = -1; - -/** - * Error code indicating that something has gone wrong with the server. - * If you get this error code, it is Parse's fault. Contact us at - * https://parse.com/help - * @property INTERNAL_SERVER_ERROR - * @static - * @final - */ -ParseError.INTERNAL_SERVER_ERROR = 1; - -/** - * Error code indicating the connection to the Parse servers failed. - * @property CONNECTION_FAILED - * @static - * @final - */ -ParseError.CONNECTION_FAILED = 100; - -/** - * Error code indicating the specified object doesn't exist. - * @property OBJECT_NOT_FOUND - * @static - * @final - */ -ParseError.OBJECT_NOT_FOUND = 101; - -/** - * Error code indicating you tried to query with a datatype that doesn't - * support it, like exact matching an array or object. - * @property INVALID_QUERY - * @static - * @final - */ -ParseError.INVALID_QUERY = 102; - -/** - * Error code indicating a missing or invalid classname. Classnames are - * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the - * only valid characters. - * @property INVALID_CLASS_NAME - * @static - * @final - */ -ParseError.INVALID_CLASS_NAME = 103; - -/** - * Error code indicating an unspecified object id. - * @property MISSING_OBJECT_ID - * @static - * @final - */ -ParseError.MISSING_OBJECT_ID = 104; - -/** - * Error code indicating an invalid key name. Keys are case-sensitive. They - * must start with a letter, and a-zA-Z0-9_ are the only valid characters. - * @property INVALID_KEY_NAME - * @static - * @final - */ -ParseError.INVALID_KEY_NAME = 105; - -/** - * Error code indicating a malformed pointer. You should not see this unless - * you have been mucking about changing internal Parse code. - * @property INVALID_POINTER - * @static - * @final - */ -ParseError.INVALID_POINTER = 106; - -/** - * Error code indicating that badly formed JSON was received upstream. This - * either indicates you have done something unusual with modifying how - * things encode to JSON, or the network is failing badly. - * @property INVALID_JSON - * @static - * @final - */ -ParseError.INVALID_JSON = 107; - -/** - * Error code indicating that the feature you tried to access is only - * available internally for testing purposes. - * @property COMMAND_UNAVAILABLE - * @static - * @final - */ -ParseError.COMMAND_UNAVAILABLE = 108; - -/** - * You must call Parse.initialize before using the Parse library. - * @property NOT_INITIALIZED - * @static - * @final - */ -ParseError.NOT_INITIALIZED = 109; - -/** - * Error code indicating that a field was set to an inconsistent type. - * @property INCORRECT_TYPE - * @static - * @final - */ -ParseError.INCORRECT_TYPE = 111; - -/** - * Error code indicating an invalid channel name. A channel name is either - * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ - * characters and starts with a letter. - * @property INVALID_CHANNEL_NAME - * @static - * @final - */ -ParseError.INVALID_CHANNEL_NAME = 112; - -/** - * Error code indicating that push is misconfigured. - * @property PUSH_MISCONFIGURED - * @static - * @final - */ -ParseError.PUSH_MISCONFIGURED = 115; - -/** - * Error code indicating that the object is too large. - * @property OBJECT_TOO_LARGE - * @static - * @final - */ -ParseError.OBJECT_TOO_LARGE = 116; - -/** - * Error code indicating that the operation isn't allowed for clients. - * @property OPERATION_FORBIDDEN - * @static - * @final - */ -ParseError.OPERATION_FORBIDDEN = 119; - -/** - * Error code indicating the result was not found in the cache. - * @property CACHE_MISS - * @static - * @final - */ -ParseError.CACHE_MISS = 120; - -/** - * Error code indicating that an invalid key was used in a nested - * JSONObject. - * @property INVALID_NESTED_KEY - * @static - * @final - */ -ParseError.INVALID_NESTED_KEY = 121; - -/** - * Error code indicating that an invalid filename was used for ParseFile. - * A valid file name contains only a-zA-Z0-9_. characters and is between 1 - * and 128 characters. - * @property INVALID_FILE_NAME - * @static - * @final - */ -ParseError.INVALID_FILE_NAME = 122; - -/** - * Error code indicating an invalid ACL was provided. - * @property INVALID_ACL - * @static - * @final - */ -ParseError.INVALID_ACL = 123; - -/** - * Error code indicating that the request timed out on the server. Typically - * this indicates that the request is too expensive to run. - * @property TIMEOUT - * @static - * @final - */ -ParseError.TIMEOUT = 124; - -/** - * Error code indicating that the email address was invalid. - * @property INVALID_EMAIL_ADDRESS - * @static - * @final - */ -ParseError.INVALID_EMAIL_ADDRESS = 125; - -/** - * Error code indicating a missing content type. - * @property MISSING_CONTENT_TYPE - * @static - * @final - */ -ParseError.MISSING_CONTENT_TYPE = 126; - -/** - * Error code indicating a missing content length. - * @property MISSING_CONTENT_LENGTH - * @static - * @final - */ -ParseError.MISSING_CONTENT_LENGTH = 127; - -/** - * Error code indicating an invalid content length. - * @property INVALID_CONTENT_LENGTH - * @static - * @final - */ -ParseError.INVALID_CONTENT_LENGTH = 128; - -/** - * Error code indicating a file that was too large. - * @property FILE_TOO_LARGE - * @static - * @final - */ -ParseError.FILE_TOO_LARGE = 129; - -/** - * Error code indicating an error saving a file. - * @property FILE_SAVE_ERROR - * @static - * @final - */ -ParseError.FILE_SAVE_ERROR = 130; - -/** - * Error code indicating that a unique field was given a value that is - * already taken. - * @property DUPLICATE_VALUE - * @static - * @final - */ -ParseError.DUPLICATE_VALUE = 137; - -/** - * Error code indicating that a role's name is invalid. - * @property INVALID_ROLE_NAME - * @static - * @final - */ -ParseError.INVALID_ROLE_NAME = 139; - -/** - * Error code indicating that an application quota was exceeded. Upgrade to - * resolve. - * @property EXCEEDED_QUOTA - * @static - * @final - */ -ParseError.EXCEEDED_QUOTA = 140; - -/** - * Error code indicating that a Cloud Code script failed. - * @property SCRIPT_FAILED - * @static - * @final - */ -ParseError.SCRIPT_FAILED = 141; - -/** - * Error code indicating that a Cloud Code validation failed. - * @property VALIDATION_ERROR - * @static - * @final - */ -ParseError.VALIDATION_ERROR = 142; - -/** - * Error code indicating that invalid image data was provided. - * @property INVALID_IMAGE_DATA - * @static - * @final - */ -ParseError.INVALID_IMAGE_DATA = 143; - -/** - * Error code indicating an unsaved file. - * @property UNSAVED_FILE_ERROR - * @static - * @final - */ -ParseError.UNSAVED_FILE_ERROR = 151; - -/** - * Error code indicating an invalid push time. - * @property INVALID_PUSH_TIME_ERROR - * @static - * @final - */ -ParseError.INVALID_PUSH_TIME_ERROR = 152; - -/** - * Error code indicating an error deleting a file. - * @property FILE_DELETE_ERROR - * @static - * @final - */ -ParseError.FILE_DELETE_ERROR = 153; - -/** - * Error code indicating that the application has exceeded its request - * limit. - * @property REQUEST_LIMIT_EXCEEDED - * @static - * @final - */ -ParseError.REQUEST_LIMIT_EXCEEDED = 155; - -/** - * Error code indicating an invalid event name. - * @property INVALID_EVENT_NAME - * @static - * @final - */ -ParseError.INVALID_EVENT_NAME = 160; - -/** - * Error code indicating that the username is missing or empty. - * @property USERNAME_MISSING - * @static - * @final - */ -ParseError.USERNAME_MISSING = 200; - -/** - * Error code indicating that the password is missing or empty. - * @property PASSWORD_MISSING - * @static - * @final - */ -ParseError.PASSWORD_MISSING = 201; - -/** - * Error code indicating that the username has already been taken. - * @property USERNAME_TAKEN - * @static - * @final - */ -ParseError.USERNAME_TAKEN = 202; - -/** - * Error code indicating that the email has already been taken. - * @property EMAIL_TAKEN - * @static - * @final - */ -ParseError.EMAIL_TAKEN = 203; - -/** - * Error code indicating that the email is missing, but must be specified. - * @property EMAIL_MISSING - * @static - * @final - */ -ParseError.EMAIL_MISSING = 204; - -/** - * Error code indicating that a user with the specified email was not found. - * @property EMAIL_NOT_FOUND - * @static - * @final - */ -ParseError.EMAIL_NOT_FOUND = 205; - -/** - * Error code indicating that a user object without a valid session could - * not be altered. - * @property SESSION_MISSING - * @static - * @final - */ -ParseError.SESSION_MISSING = 206; - -/** - * Error code indicating that a user can only be created through signup. - * @property MUST_CREATE_USER_THROUGH_SIGNUP - * @static - * @final - */ -ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; - -/** - * Error code indicating that an an account being linked is already linked - * to another user. - * @property ACCOUNT_ALREADY_LINKED - * @static - * @final - */ -ParseError.ACCOUNT_ALREADY_LINKED = 208; - -/** - * Error code indicating that the current session token is invalid. - * @property INVALID_SESSION_TOKEN - * @static - * @final - */ -ParseError.INVALID_SESSION_TOKEN = 209; - -/** - * Error code indicating that a user cannot be linked to an account because - * that account's id could not be found. - * @property LINKED_ID_MISSING - * @static - * @final - */ -ParseError.LINKED_ID_MISSING = 250; - -/** - * Error code indicating that a user with a linked (e.g. Facebook) account - * has an invalid session. - * @property INVALID_LINKED_SESSION - * @static - * @final - */ -ParseError.INVALID_LINKED_SESSION = 251; - -/** - * Error code indicating that a service being linked (e.g. Facebook or - * Twitter) is unsupported. - * @property UNSUPPORTED_SERVICE - * @static - * @final - */ -ParseError.UNSUPPORTED_SERVICE = 252; - -/** - * Error code indicating that there were multiple errors. Aggregate errors - * have an "errors" property, which is an array of error objects with more - * detail about each error that occurred. - * @property AGGREGATE_ERROR - * @static - * @final - */ -ParseError.AGGREGATE_ERROR = 600; - -/** - * Error code indicating the client was unable to read an input file. - * @property FILE_READ_ERROR - * @static - * @final - */ -ParseError.FILE_READ_ERROR = 601; - -/** - * Error code indicating a real error code is unavailable because - * we had to use an XDomainRequest object to allow CORS requests in - * Internet Explorer, which strips the body from HTTP responses that have - * a non-2XX status code. - * @property X_DOMAIN_REQUEST - * @static - * @final - */ -ParseError.X_DOMAIN_REQUEST = 602; \ No newline at end of file diff --git a/lib/browser/ParseFile.js b/lib/browser/ParseFile.js deleted file mode 100644 index 48efdb9d8..000000000 --- a/lib/browser/ParseFile.js +++ /dev/null @@ -1,291 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; - -function b64Digit(number) { - if (number < 26) { - return String.fromCharCode(65 + number); - } - if (number < 52) { - return String.fromCharCode(97 + (number - 26)); - } - if (number < 62) { - return String.fromCharCode(48 + (number - 52)); - } - if (number === 62) { - return '+'; - } - if (number === 63) { - return '/'; - } - throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); -} - -/** - * A Parse.File is a local representation of a file that is saved to the Parse - * cloud. - * @class Parse.File - * @constructor - * @param name {String} The file's name. This will be prefixed by a unique - * value once the file has finished saving. The file name must begin with - * an alphanumeric character, and consist of alphanumeric characters, - * periods, spaces, underscores, or dashes. - * @param data {Array} The data for the file, as either: - * 1. an Array of byte value Numbers, or - * 2. an Object like { base64: "..." } with a base64-encoded String. - * 3. a File object selected with a file upload control. (3) only works - * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. - * For example:
                      - * var fileUploadControl = $("#profilePhotoFileUpload")[0];
                      - * if (fileUploadControl.files.length > 0) {
                      - *   var file = fileUploadControl.files[0];
                      - *   var name = "photo.jpg";
                      - *   var parseFile = new Parse.File(name, file);
                      - *   parseFile.save().then(function() {
                      - *     // The file has been saved to Parse.
                      - *   }, function(error) {
                      - *     // The file either could not be read, or could not be saved to Parse.
                      - *   });
                      - * }
                      - * @param type {String} Optional Content-Type header to use for the file. If - * this is omitted, the content type will be inferred from the name's - * extension. - */ - -var ParseFile = function () { - function ParseFile(name, data, type) { - (0, _classCallCheck3.default)(this, ParseFile); - - var specifiedType = type || ''; - - this._name = name; - - if (data !== undefined) { - if (Array.isArray(data)) { - this._source = { - format: 'base64', - base64: ParseFile.encodeBase64(data), - type: specifiedType - }; - } else if (typeof File !== 'undefined' && data instanceof File) { - this._source = { - format: 'file', - file: data, - type: specifiedType - }; - } else if (data && typeof data.base64 === 'string') { - var _base = data.base64; - var commaIndex = _base.indexOf(','); - - if (commaIndex !== -1) { - var matches = dataUriRegexp.exec(_base.slice(0, commaIndex + 1)); - // if data URI with type and charset, there will be 4 matches. - this._source = { - format: 'base64', - base64: _base.slice(commaIndex + 1), - type: matches[1] - }; - } else { - this._source = { - format: 'base64', - base64: _base, - type: specifiedType - }; - } - } else { - throw new TypeError('Cannot create a Parse.File with that data.'); - } - } - } - - /** - * Gets the name of the file. Before save is called, this is the filename - * given by the user. After save is called, that name gets prefixed with a - * unique identifier. - * @method name - * @return {String} - */ - - (0, _createClass3.default)(ParseFile, [{ - key: 'name', - value: function () { - return this._name; - } - - /** - * Gets the url of the file. It is only available after you save the file or - * after you get the file from a Parse.Object. - * @method url - * @param {Object} options An object to specify url options - * @return {String} - */ - - }, { - key: 'url', - value: function (options) { - options = options || {}; - if (!this._url) { - return; - } - if (options.forceSecure) { - return this._url.replace(/^http:\/\//i, 'https://'); - } else { - return this._url; - } - } - - /** - * Saves the file to the Parse cloud. - * @method save - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} Promise that is resolved when the save finishes. - */ - - }, { - key: 'save', - value: function (options) { - var _this = this; - - options = options || {}; - var controller = _CoreManager2.default.getFileController(); - if (!this._previousSave) { - if (this._source.format === 'file') { - this._previousSave = controller.saveFile(this._name, this._source).then(function (res) { - _this._name = res.name; - _this._url = res.url; - return _this; - }); - } else { - this._previousSave = controller.saveBase64(this._name, this._source).then(function (res) { - _this._name = res.name; - _this._url = res.url; - return _this; - }); - } - } - if (this._previousSave) { - return this._previousSave._thenRunCallbacks(options); - } - } - }, { - key: 'toJSON', - value: function () { - return { - __type: 'File', - name: this._name, - url: this._url - }; - } - }, { - key: 'equals', - value: function (other) { - if (this === other) { - return true; - } - // Unsaved Files are never equal, since they will be saved to different URLs - return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; - } - }], [{ - key: 'fromJSON', - value: function (obj) { - if (obj.__type !== 'File') { - throw new TypeError('JSON object does not represent a ParseFile'); - } - var file = new ParseFile(obj.name); - file._url = obj.url; - return file; - } - }, { - key: 'encodeBase64', - value: function (bytes) { - var chunks = []; - chunks.length = Math.ceil(bytes.length / 3); - for (var i = 0; i < chunks.length; i++) { - var b1 = bytes[i * 3]; - var b2 = bytes[i * 3 + 1] || 0; - var b3 = bytes[i * 3 + 2] || 0; - - var has2 = i * 3 + 1 < bytes.length; - var has3 = i * 3 + 2 < bytes.length; - - chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); - } - - return chunks.join(''); - } - }]); - return ParseFile; -}(); - -exports.default = ParseFile; - -var DefaultController = { - saveFile: function (name, source) { - if (source.format !== 'file') { - throw new Error('saveFile can only be used with File-type sources.'); - } - // To directly upload a File, we use a REST-style AJAX request - var headers = { - 'X-Parse-Application-ID': _CoreManager2.default.get('APPLICATION_ID'), - 'X-Parse-JavaScript-Key': _CoreManager2.default.get('JAVASCRIPT_KEY'), - 'Content-Type': source.type || (source.file ? source.file.type : null) - }; - var url = _CoreManager2.default.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += 'files/' + name; - return _CoreManager2.default.getRESTController().ajax('POST', url, source.file, headers); - }, - - saveBase64: function (name, source) { - if (source.format !== 'base64') { - throw new Error('saveBase64 can only be used with Base64-type sources.'); - } - var data = { - base64: source.base64 - }; - if (source.type) { - data._ContentType = source.type; - } - - return _CoreManager2.default.getRESTController().request('POST', 'files/' + name, data); - } -}; - -_CoreManager2.default.setFileController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseGeoPoint.js b/lib/browser/ParseGeoPoint.js deleted file mode 100644 index 98691f85b..000000000 --- a/lib/browser/ParseGeoPoint.js +++ /dev/null @@ -1,235 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new GeoPoint with any of the following forms:
                      - *
                      - *   new GeoPoint(otherGeoPoint)
                      - *   new GeoPoint(30, 30)
                      - *   new GeoPoint([30, 30])
                      - *   new GeoPoint({latitude: 30, longitude: 30})
                      - *   new GeoPoint()  // defaults to (0, 0)
                      - *   
                      - * @class Parse.GeoPoint - * @constructor - * - *

                      Represents a latitude / longitude point that may be associated - * with a key in a ParseObject or used as a reference point for geo queries. - * This allows proximity-based queries on the key.

                      - * - *

                      Only one key in a class may contain a GeoPoint.

                      - * - *

                      Example:

                      - *   var point = new Parse.GeoPoint(30.0, -20.0);
                      - *   var object = new Parse.Object("PlaceObject");
                      - *   object.set("location", point);
                      - *   object.save();

                      - */ -var ParseGeoPoint = function () { - function ParseGeoPoint(arg1, arg2) { - (0, _classCallCheck3.default)(this, ParseGeoPoint); - - if (Array.isArray(arg1)) { - ParseGeoPoint._validate(arg1[0], arg1[1]); - this._latitude = arg1[0]; - this._longitude = arg1[1]; - } else if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { - ParseGeoPoint._validate(arg1.latitude, arg1.longitude); - this._latitude = arg1.latitude; - this._longitude = arg1.longitude; - } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { - ParseGeoPoint._validate(arg1, arg2); - this._latitude = arg1; - this._longitude = arg2; - } else { - this._latitude = 0; - this._longitude = 0; - } - } - - /** - * North-south portion of the coordinate, in range [-90, 90]. - * Throws an exception if set out of range in a modern browser. - * @property latitude - * @type Number - */ - - (0, _createClass3.default)(ParseGeoPoint, [{ - key: 'toJSON', - - /** - * Returns a JSON representation of the GeoPoint, suitable for Parse. - * @method toJSON - * @return {Object} - */ - value: function () { - ParseGeoPoint._validate(this._latitude, this._longitude); - return { - __type: 'GeoPoint', - latitude: this._latitude, - longitude: this._longitude - }; - } - }, { - key: 'equals', - value: function (other) { - return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; - } - - /** - * Returns the distance from this GeoPoint to another in radians. - * @method radiansTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'radiansTo', - value: function (point) { - var d2r = Math.PI / 180.0; - var lat1rad = this.latitude * d2r; - var long1rad = this.longitude * d2r; - var lat2rad = point.latitude * d2r; - var long2rad = point.longitude * d2r; - - var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); - var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); - // Square of half the straight line chord distance between both points. - var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; - a = Math.min(1.0, a); - return 2 * Math.asin(Math.sqrt(a)); - } - - /** - * Returns the distance from this GeoPoint to another in kilometers. - * @method kilometersTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'kilometersTo', - value: function (point) { - return this.radiansTo(point) * 6371.0; - } - - /** - * Returns the distance from this GeoPoint to another in miles. - * @method milesTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'milesTo', - value: function (point) { - return this.radiansTo(point) * 3958.8; - } - - /** - * Throws an exception if the given lat-long is out of bounds. - */ - - }, { - key: 'latitude', - get: function () { - return this._latitude; - }, - set: function (val) { - ParseGeoPoint._validate(val, this.longitude); - this._latitude = val; - } - - /** - * East-west portion of the coordinate, in range [-180, 180]. - * Throws if set out of range in a modern browser. - * @property longitude - * @type Number - */ - - }, { - key: 'longitude', - get: function () { - return this._longitude; - }, - set: function (val) { - ParseGeoPoint._validate(this.latitude, val); - this._longitude = val; - } - }], [{ - key: '_validate', - value: function (latitude, longitude) { - if (latitude !== latitude || longitude !== longitude) { - throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); - } - if (latitude < -90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); - } - if (latitude > 90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); - } - if (longitude < -180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); - } - if (longitude > 180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); - } - } - - /** - * Creates a GeoPoint with the user's current location, if available. - * Calls options.success with a new GeoPoint instance or calls options.error. - * @method current - * @param {Object} options An object with success and error callbacks. - * @static - */ - - }, { - key: 'current', - value: function (options) { - var promise = new _ParsePromise2.default(); - navigator.geolocation.getCurrentPosition(function (location) { - promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); - }, function (error) { - promise.reject(error); - }); - - return promise._thenRunCallbacks(options); - } - }]); - return ParseGeoPoint; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseGeoPoint; \ No newline at end of file diff --git a/lib/browser/ParseHooks.js b/lib/browser/ParseHooks.js deleted file mode 100644 index a2057e899..000000000 --- a/lib/browser/ParseHooks.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _promise = require('babel-runtime/core-js/promise'); - -var _promise2 = _interopRequireDefault(_promise); - -exports.getFunctions = getFunctions; -exports.getTriggers = getTriggers; -exports.getFunction = getFunction; -exports.getTrigger = getTrigger; -exports.createFunction = createFunction; -exports.createTrigger = createTrigger; -exports.create = create; -exports.updateFunction = updateFunction; -exports.updateTrigger = updateTrigger; -exports.update = update; -exports.removeFunction = removeFunction; -exports.removeTrigger = removeTrigger; -exports.remove = remove; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function getFunctions() { - return _CoreManager2.default.getHooksController().get("functions"); -} - -function getTriggers() { - return _CoreManager2.default.getHooksController().get("triggers"); -} - -function getFunction(name) { - return _CoreManager2.default.getHooksController().get("functions", name); -} - -function getTrigger(className, triggerName) { - return _CoreManager2.default.getHooksController().get("triggers", className, triggerName); -} - -function createFunction(functionName, url) { - return create({ functionName: functionName, url: url }); -} - -function createTrigger(className, triggerName, url) { - return create({ className: className, triggerName: triggerName, url: url }); -} - -function create(hook) { - return _CoreManager2.default.getHooksController().create(hook); -} - -function updateFunction(functionName, url) { - return update({ functionName: functionName, url: url }); -} - -function updateTrigger(className, triggerName, url) { - return update({ className: className, triggerName: triggerName, url: url }); -} - -function update(hook) { - return _CoreManager2.default.getHooksController().update(hook); -} - -function removeFunction(functionName) { - return remove({ functionName: functionName }); -} - -function removeTrigger(className, triggerName) { - return remove({ className: className, triggerName: triggerName }); -} - -function remove(hook) { - return _CoreManager2.default.getHooksController().remove(hook); -} - -var DefaultController = { - get: function (type, functionName, triggerName) { - var url = "/hooks/" + type; - if (functionName) { - url += "/" + functionName; - if (triggerName) { - url += "/" + triggerName; - } - } - return this.sendRequest("GET", url); - }, - create: function (hook) { - var url; - if (hook.functionName && hook.url) { - url = "/hooks/functions"; - } else if (hook.className && hook.triggerName && hook.url) { - url = "/hooks/triggers"; - } else { - return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest("POST", url, hook); - }, - remove: function (hook) { - var url; - if (hook.functionName) { - url = "/hooks/functions/" + hook.functionName; - delete hook.functionName; - } else if (hook.className && hook.triggerName) { - url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; - delete hook.className; - delete hook.triggerName; - } else { - return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest("PUT", url, { "__op": "Delete" }); - }, - update: function (hook) { - var url; - if (hook.functionName && hook.url) { - url = "/hooks/functions/" + hook.functionName; - delete hook.functionName; - } else if (hook.className && hook.triggerName && hook.url) { - url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; - delete hook.className; - delete hook.triggerName; - } else { - return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest('PUT', url, hook); - }, - sendRequest: function (method, url, body) { - return _CoreManager2.default.getRESTController().request(method, url, body, { useMasterKey: true }).then(function (res) { - var decoded = (0, _decode2.default)(res); - if (decoded) { - return _ParsePromise2.default.as(decoded); - } - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); - }); - } -}; - -_CoreManager2.default.setHooksController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseInstallation.js b/lib/browser/ParseInstallation.js deleted file mode 100644 index 02d7be1d8..000000000 --- a/lib/browser/ParseInstallation.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var Installation = function (_ParseObject) { - (0, _inherits3.default)(Installation, _ParseObject); - - function Installation(attributes) { - (0, _classCallCheck3.default)(this, Installation); - - var _this = (0, _possibleConstructorReturn3.default)(this, (Installation.__proto__ || (0, _getPrototypeOf2.default)(Installation)).call(this, '_Installation')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - return _this; - } - - return Installation; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = Installation; - -_ParseObject3.default.registerSubclass('_Installation', Installation); \ No newline at end of file diff --git a/lib/browser/ParseLiveQuery.js b/lib/browser/ParseLiveQuery.js deleted file mode 100644 index a3e5fe31d..000000000 --- a/lib/browser/ParseLiveQuery.js +++ /dev/null @@ -1,241 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _EventEmitter = require('./EventEmitter'); - -var _EventEmitter2 = _interopRequireDefault(_EventEmitter); - -var _LiveQueryClient = require('./LiveQueryClient'); - -var _LiveQueryClient2 = _interopRequireDefault(_LiveQueryClient); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function open() { - var LiveQueryController = _CoreManager2.default.getLiveQueryController(); - LiveQueryController.open(); -} - -function close() { - var LiveQueryController = _CoreManager2.default.getLiveQueryController(); - LiveQueryController.close(); -} - -/** - * - * We expose three events to help you monitor the status of the WebSocket connection: - * - *

                      Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                      - * Parse.LiveQuery.on('open', () => {
                      - * 
                      - * });

                      - * - *

                      Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                      - * Parse.LiveQuery.on('close', () => {
                      - * 
                      - * });

                      - * - *

                      Error - When some network error or LiveQuery server error happens, you'll get this event. - * - *

                      - * Parse.LiveQuery.on('error', (error) => {
                      - * 
                      - * });

                      - * - * @class Parse.LiveQuery - * @static - * - */ -var LiveQuery = new _EventEmitter2.default(); - -/** - * After open is called, the LiveQuery will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ -LiveQuery.open = open; - -/** - * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). - * This function will close the WebSocket connection to the LiveQuery server, - * cancel the auto reconnect, and unsubscribe all subscriptions based on it. - * If you call query.subscribe() after this, we'll create a new WebSocket - * connection to the LiveQuery server. - * - * @method close - */ - -LiveQuery.close = close; -// Register a default onError callback to make sure we do not crash on error -LiveQuery.on('error', function () {}); - -exports.default = LiveQuery; - -function getSessionToken() { - var controller = _CoreManager2.default.getUserController(); - return controller.currentUserAsync().then(function (currentUser) { - return currentUser ? currentUser.getSessionToken() : undefined; - }); -} - -function getLiveQueryClient() { - return _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient(); -} - -var defaultLiveQueryClient = void 0; -var DefaultLiveQueryController = { - setDefaultLiveQueryClient: function (liveQueryClient) { - defaultLiveQueryClient = liveQueryClient; - }, - getDefaultLiveQueryClient: function () { - if (defaultLiveQueryClient) { - return _ParsePromise2.default.as(defaultLiveQueryClient); - } - - return getSessionToken().then(function (sessionToken) { - var liveQueryServerURL = _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); - - if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL - if (!liveQueryServerURL) { - var tempServerURL = _CoreManager2.default.get('SERVER_URL'); - var protocol = 'ws://'; - // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix - if (tempServerURL.indexOf('https') === 0) { - protocol = 'wss://'; - } - var host = tempServerURL.replace(/^https?:\/\//, ''); - liveQueryServerURL = protocol + host; - _CoreManager2.default.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); - } - - var applicationId = _CoreManager2.default.get('APPLICATION_ID'); - var javascriptKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); - var masterKey = _CoreManager2.default.get('MASTER_KEY'); - // Get currentUser sessionToken if possible - defaultLiveQueryClient = new _LiveQueryClient2.default({ - applicationId: applicationId, - serverURL: liveQueryServerURL, - javascriptKey: javascriptKey, - masterKey: masterKey, - sessionToken: sessionToken - }); - // Register a default onError callback to make sure we do not crash on error - // Cannot create these events on a nested way because of EventEmiiter from React Native - defaultLiveQueryClient.on('error', function (error) { - LiveQuery.emit('error', error); - }); - defaultLiveQueryClient.on('open', function () { - LiveQuery.emit('open'); - }); - defaultLiveQueryClient.on('close', function () { - LiveQuery.emit('close'); - }); - - return defaultLiveQueryClient; - }); - }, - open: function () { - var _this = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this.resolve(liveQueryClient.open()); - }); - }, - close: function () { - var _this2 = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this2.resolve(liveQueryClient.close()); - }); - }, - subscribe: function (query) { - var _this3 = this; - - var subscriptionWrap = new _EventEmitter2.default(); - - getLiveQueryClient().then(function (liveQueryClient) { - if (liveQueryClient.shouldOpen()) { - liveQueryClient.open(); - } - var promiseSessionToken = getSessionToken(); - // new event emitter - return promiseSessionToken.then(function (sessionToken) { - - var subscription = liveQueryClient.subscribe(query, sessionToken); - // enter, leave create, etc - - subscriptionWrap.id = subscription.id; - subscriptionWrap.query = subscription.query; - subscriptionWrap.sessionToken = subscription.sessionToken; - subscriptionWrap.unsubscribe = subscription.unsubscribe; - // Cannot create these events on a nested way because of EventEmiiter from React Native - subscription.on('open', function () { - subscriptionWrap.emit('open'); - }); - subscription.on('create', function (object) { - subscriptionWrap.emit('create', object); - }); - subscription.on('update', function (object) { - subscriptionWrap.emit('update', object); - }); - subscription.on('enter', function (object) { - subscriptionWrap.emit('enter', object); - }); - subscription.on('leave', function (object) { - subscriptionWrap.emit('leave', object); - }); - subscription.on('delete', function (object) { - subscriptionWrap.emit('delete', object); - }); - - _this3.resolve(); - }); - }); - return subscriptionWrap; - }, - unsubscribe: function (subscription) { - var _this4 = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this4.resolve(liveQueryClient.unsubscribe(subscription)); - }); - }, - _clearCachedDefaultClient: function () { - defaultLiveQueryClient = null; - } -}; - -_CoreManager2.default.setLiveQueryController(DefaultLiveQueryController); \ No newline at end of file diff --git a/lib/browser/ParseObject.js b/lib/browser/ParseObject.js deleted file mode 100644 index f08795e52..000000000 --- a/lib/browser/ParseObject.js +++ /dev/null @@ -1,2001 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _defineProperty = require('babel-runtime/core-js/object/define-property'); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -var _create = require('babel-runtime/core-js/object/create'); - -var _create2 = _interopRequireDefault(_create); - -var _freeze = require('babel-runtime/core-js/object/freeze'); - -var _freeze2 = _interopRequireDefault(_freeze); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _canBeSerialized = require('./canBeSerialized'); - -var _canBeSerialized2 = _interopRequireDefault(_canBeSerialized); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _equals = require('./equals'); - -var _equals2 = _interopRequireDefault(_equals); - -var _escape2 = require('./escape'); - -var _escape3 = _interopRequireDefault(_escape2); - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _parseDate = require('./parseDate'); - -var _parseDate2 = _interopRequireDefault(_parseDate); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseOp = require('./ParseOp'); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseQuery = require('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _SingleInstanceStateController = require('./SingleInstanceStateController'); - -var SingleInstanceStateController = _interopRequireWildcard(_SingleInstanceStateController); - -var _unique = require('./unique'); - -var _unique2 = _interopRequireDefault(_unique); - -var _UniqueInstanceStateController = require('./UniqueInstanceStateController'); - -var UniqueInstanceStateController = _interopRequireWildcard(_UniqueInstanceStateController); - -var _unsavedChildren = require('./unsavedChildren'); - -var _unsavedChildren2 = _interopRequireDefault(_unsavedChildren); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -// Mapping of class names to constructors, so we can populate objects from the -// server with appropriate subclasses of ParseObject -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var classMap = {}; - -// Global counter for generating unique local Ids -var localCount = 0; -// Global counter for generating unique Ids for non-single-instance objects -var objectCount = 0; -// On web clients, objects are single-instance: any two objects with the same Id -// will have the same attributes. However, this may be dangerous default -// behavior in a server scenario -var singleInstance = !_CoreManager2.default.get('IS_NODE'); -if (singleInstance) { - _CoreManager2.default.setObjectStateController(SingleInstanceStateController); -} else { - _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); -} - -function getServerUrlPath() { - var serverUrl = _CoreManager2.default.get('SERVER_URL'); - if (serverUrl[serverUrl.length - 1] !== '/') { - serverUrl += '/'; - } - var url = serverUrl.replace(/https?:\/\//, ''); - return url.substr(url.indexOf('/')); -} - -/** - * Creates a new model with defined attributes. - * - *

                      You won't normally call this method directly. It is recommended that - * you use a subclass of Parse.Object instead, created by calling - * extend.

                      - * - *

                      However, if you don't want to use a subclass, or aren't sure which - * subclass is appropriate, you can use this form:

                      - *     var object = new Parse.Object("ClassName");
                      - * 
                      - * That is basically equivalent to:
                      - *     var MyClass = Parse.Object.extend("ClassName");
                      - *     var object = new MyClass();
                      - * 

                      - * - * @class Parse.Object - * @constructor - * @param {String} className The class name for the object - * @param {Object} attributes The initial set of data to store in the object. - * @param {Object} options The options for this object instance. - */ - -var ParseObject = function () { - /** - * The ID of this object, unique within its class. - * @property id - * @type String - */ - function ParseObject(className, attributes, options) { - (0, _classCallCheck3.default)(this, ParseObject); - - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - var toSet = null; - this._objCount = objectCount++; - if (typeof className === 'string') { - this.className = className; - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - toSet = attributes; - } - } else if (className && (typeof className === 'undefined' ? 'undefined' : (0, _typeof3.default)(className)) === 'object') { - this.className = className.className; - toSet = {}; - for (var attr in className) { - if (attr !== 'className') { - toSet[attr] = className[attr]; - } - } - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - options = attributes; - } - } - if (toSet && !this.set(toSet, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - - /** Prototype getters / setters **/ - - (0, _createClass3.default)(ParseObject, [{ - key: '_getId', - - /** Private methods **/ - - /** - * Returns a local or server Id used uniquely identify this object - */ - value: function () { - if (typeof this.id === 'string') { - return this.id; - } - if (typeof this._localId === 'string') { - return this._localId; - } - var localId = 'local' + String(localCount++); - this._localId = localId; - return localId; - } - - /** - * Returns a unique identifier used to pull data from the State Controller. - */ - - }, { - key: '_getStateIdentifier', - value: function () { - if (singleInstance) { - var _id = this.id; - if (!_id) { - _id = this._getId(); - } - return { - id: _id, - className: this.className - }; - } else { - return this; - } - } - }, { - key: '_getServerData', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return stateController.getServerData(this._getStateIdentifier()); - } - }, { - key: '_clearServerData', - value: function () { - var serverData = this._getServerData(); - var unset = {}; - for (var attr in serverData) { - unset[attr] = undefined; - } - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.setServerData(this._getStateIdentifier(), unset); - } - }, { - key: '_getPendingOps', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return stateController.getPendingOps(this._getStateIdentifier()); - } - }, { - key: '_clearPendingOps', - value: function () { - var pending = this._getPendingOps(); - var latest = pending[pending.length - 1]; - var keys = (0, _keys2.default)(latest); - keys.forEach(function (key) { - delete latest[key]; - }); - } - }, { - key: '_getDirtyObjectAttributes', - value: function () { - var attributes = this.attributes; - var stateController = _CoreManager2.default.getObjectStateController(); - var objectCache = stateController.getObjectCache(this._getStateIdentifier()); - var dirty = {}; - for (var attr in attributes) { - var val = attributes[attr]; - if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof ParseObject) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { - // Due to the way browsers construct maps, the key order will not change - // unless the object is changed - try { - var json = (0, _encode2.default)(val, false, true); - var stringified = (0, _stringify2.default)(json); - if (objectCache[attr] !== stringified) { - dirty[attr] = val; - } - } catch (e) { - // Error occurred, possibly by a nested unsaved pointer in a mutable container - // No matter how it happened, it indicates a change in the attribute - dirty[attr] = val; - } - } - } - return dirty; - } - }, { - key: '_toFullJSON', - value: function (seen) { - var json = this.toJSON(seen); - json.__type = 'Object'; - json.className = this.className; - return json; - } - }, { - key: '_getSaveJSON', - value: function () { - var pending = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - var json = {}; - - for (var attr in dirtyObjects) { - json[attr] = new _ParseOp.SetOp(dirtyObjects[attr]).toJSON(); - } - for (attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - return json; - } - }, { - key: '_getSaveParams', - value: function () { - var method = this.id ? 'PUT' : 'POST'; - var body = this._getSaveJSON(); - var path = 'classes/' + this.className; - if (this.id) { - path += '/' + this.id; - } else if (this.className === '_User') { - path = 'users'; - } - return { - method: method, - body: body, - path: path - }; - } - }, { - key: '_finishFetch', - value: function (serverData) { - if (!this.id && serverData.objectId) { - this.id = serverData.objectId; - } - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.initializeState(this._getStateIdentifier()); - var decoded = {}; - for (var attr in serverData) { - if (attr === 'ACL') { - decoded[attr] = new _ParseACL2.default(serverData[attr]); - } else if (attr !== 'objectId') { - decoded[attr] = (0, _decode2.default)(serverData[attr]); - if (decoded[attr] instanceof _ParseRelation2.default) { - decoded[attr]._ensureParentAndKey(this, attr); - } - } - } - if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = (0, _parseDate2.default)(decoded.createdAt); - } - if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = (0, _parseDate2.default)(decoded.updatedAt); - } - if (!decoded.updatedAt && decoded.createdAt) { - decoded.updatedAt = decoded.createdAt; - } - stateController.commitServerChanges(this._getStateIdentifier(), decoded); - } - }, { - key: '_setExisted', - value: function (existed) { - var stateController = _CoreManager2.default.getObjectStateController(); - var state = stateController.getState(this._getStateIdentifier()); - if (state) { - state.existed = existed; - } - } - }, { - key: '_migrateId', - value: function (serverId) { - if (this._localId && serverId) { - if (singleInstance) { - var stateController = _CoreManager2.default.getObjectStateController(); - var oldState = stateController.removeState(this._getStateIdentifier()); - this.id = serverId; - delete this._localId; - if (oldState) { - stateController.initializeState(this._getStateIdentifier(), oldState); - } - } else { - this.id = serverId; - delete this._localId; - } - } - } - }, { - key: '_handleSaveResponse', - value: function (response, status) { - var changes = {}; - - var stateController = _CoreManager2.default.getObjectStateController(); - var pending = stateController.popPendingState(this._getStateIdentifier()); - for (var attr in pending) { - if (pending[attr] instanceof _ParseOp.RelationOp) { - changes[attr] = pending[attr].applyTo(undefined, this, attr); - } else if (!(attr in response)) { - // Only SetOps and UnsetOps should not come back with results - changes[attr] = pending[attr].applyTo(undefined); - } - } - for (attr in response) { - if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { - changes[attr] = (0, _parseDate2.default)(response[attr]); - } else if (attr === 'ACL') { - changes[attr] = new _ParseACL2.default(response[attr]); - } else if (attr !== 'objectId') { - changes[attr] = (0, _decode2.default)(response[attr]); - if (changes[attr] instanceof _ParseOp.UnsetOp) { - changes[attr] = undefined; - } - } - } - if (changes.createdAt && !changes.updatedAt) { - changes.updatedAt = changes.createdAt; - } - - this._migrateId(response.objectId); - - if (status !== 201) { - this._setExisted(true); - } - - stateController.commitServerChanges(this._getStateIdentifier(), changes); - } - }, { - key: '_handleSaveError', - value: function () { - this._getPendingOps(); - - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.mergeFirstPendingState(this._getStateIdentifier()); - } - - /** Public methods **/ - - }, { - key: 'initialize', - value: function () {} - // NOOP - - - /** - * Returns a JSON version of the object suitable for saving to Parse. - * @method toJSON - * @return {Object} - */ - - }, { - key: 'toJSON', - value: function (seen) { - var seenEntry = this.id ? this.className + ':' + this.id : this; - var seen = seen || [seenEntry]; - var json = {}; - var attrs = this.attributes; - for (var attr in attrs) { - if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { - json[attr] = attrs[attr].toJSON(); - } else { - json[attr] = (0, _encode2.default)(attrs[attr], false, false, seen); - } - } - var pending = this._getPendingOps(); - for (var attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - - if (this.id) { - json.objectId = this.id; - } - return json; - } - - /** - * Determines whether this ParseObject is equal to another ParseObject - * @method equals - * @return {Boolean} - */ - - }, { - key: 'equals', - value: function (other) { - if (this === other) { - return true; - } - return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; - } - - /** - * Returns true if this object has been modified since its last - * save/refresh. If an attribute is specified, it returns true only if that - * particular attribute has been modified since the last save/refresh. - * @method dirty - * @param {String} attr An attribute name (optional). - * @return {Boolean} - */ - - }, { - key: 'dirty', - value: function (attr) { - if (!this.id) { - return true; - } - var pendingOps = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - if (attr) { - if (dirtyObjects.hasOwnProperty(attr)) { - return true; - } - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i].hasOwnProperty(attr)) { - return true; - } - } - return false; - } - if ((0, _keys2.default)(pendingOps[0]).length !== 0) { - return true; - } - if ((0, _keys2.default)(dirtyObjects).length !== 0) { - return true; - } - return false; - } - - /** - * Returns an array of keys that have been modified since last save/refresh - * @method dirtyKeys - * @return {Array of string} - */ - - }, { - key: 'dirtyKeys', - value: function () { - var pendingOps = this._getPendingOps(); - var keys = {}; - for (var i = 0; i < pendingOps.length; i++) { - for (var attr in pendingOps[i]) { - keys[attr] = true; - } - } - var dirtyObjects = this._getDirtyObjectAttributes(); - for (var attr in dirtyObjects) { - keys[attr] = true; - } - return (0, _keys2.default)(keys); - } - - /** - * Gets a Pointer referencing this Object. - * @method toPointer - * @return {Object} - */ - - }, { - key: 'toPointer', - value: function () { - if (!this.id) { - throw new Error('Cannot create a pointer to an unsaved ParseObject'); - } - return { - __type: 'Pointer', - className: this.className, - objectId: this.id - }; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'get', - value: function (attr) { - return this.attributes[attr]; - } - - /** - * Gets a relation on the given class for the attribute. - * @method relation - * @param String attr The attribute to get the relation for. - */ - - }, { - key: 'relation', - value: function (attr) { - var value = this.get(attr); - if (value) { - if (!(value instanceof _ParseRelation2.default)) { - throw new Error('Called relation() on non-relation field ' + attr); - } - value._ensureParentAndKey(this, attr); - return value; - } - return new _ParseRelation2.default(this, attr); - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'escape', - value: function (attr) { - var val = this.attributes[attr]; - if (val == null) { - return ''; - } - - if (typeof val !== 'string') { - if (typeof val.toString !== 'function') { - return ''; - } - val = val.toString(); - } - return (0, _escape3.default)(val); - } - - /** - * Returns true if the attribute contains a value that is not - * null or undefined. - * @method has - * @param {String} attr The string name of the attribute. - * @return {Boolean} - */ - - }, { - key: 'has', - value: function (attr) { - var attributes = this.attributes; - if (attributes.hasOwnProperty(attr)) { - return attributes[attr] != null; - } - return false; - } - - /** - * Sets a hash of model attributes on the object. - * - *

                      You can call it with an object containing keys and values, or with one - * key and value. For example:

                      -     *   gameTurn.set({
                      -     *     player: player1,
                      -     *     diceRoll: 2
                      -     *   }, {
                      -     *     error: function(gameTurnAgain, error) {
                      -     *       // The set failed validation.
                      -     *     }
                      -     *   });
                      -     *
                      -     *   game.set("currentPlayer", player2, {
                      -     *     error: function(gameTurnAgain, error) {
                      -     *       // The set failed validation.
                      -     *     }
                      -     *   });
                      -     *
                      -     *   game.set("finished", true);

                      - * - * @method set - * @param {String} key The key to set. - * @param {} value The value to give it. - * @param {Object} options A set of options for the set. - * The only supported option is error. - * @return {Boolean} true if the set succeeded. - */ - - }, { - key: 'set', - value: function (key, value, options) { - var changes = {}; - var newOps = {}; - if (key && (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'object') { - changes = key; - options = value; - } else if (typeof key === 'string') { - changes[key] = value; - } else { - return this; - } - - options = options || {}; - var readonly = []; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var k in changes) { - if (k === 'createdAt' || k === 'updatedAt') { - // This property is read-only, but for legacy reasons we silently - // ignore it - continue; - } - if (readonly.indexOf(k) > -1) { - throw new Error('Cannot modify readonly attribute: ' + k); - } - if (options.unset) { - newOps[k] = new _ParseOp.UnsetOp(); - } else if (changes[k] instanceof _ParseOp.Op) { - newOps[k] = changes[k]; - } else if (changes[k] && (0, _typeof3.default)(changes[k]) === 'object' && typeof changes[k].__op === 'string') { - newOps[k] = (0, _ParseOp.opFromJSON)(changes[k]); - } else if (k === 'objectId' || k === 'id') { - if (typeof changes[k] === 'string') { - this.id = changes[k]; - } - } else if (k === 'ACL' && (0, _typeof3.default)(changes[k]) === 'object' && !(changes[k] instanceof _ParseACL2.default)) { - newOps[k] = new _ParseOp.SetOp(new _ParseACL2.default(changes[k])); - } else { - newOps[k] = new _ParseOp.SetOp(changes[k]); - } - } - - // Calculate new values - var currentAttributes = this.attributes; - var newValues = {}; - for (var attr in newOps) { - if (newOps[attr] instanceof _ParseOp.RelationOp) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); - } else if (!(newOps[attr] instanceof _ParseOp.UnsetOp)) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); - } - } - - // Validate changes - if (!options.ignoreValidation) { - var validation = this.validate(newValues); - if (validation) { - if (typeof options.error === 'function') { - options.error(this, validation); - } - return false; - } - } - - // Consolidate Ops - var pendingOps = this._getPendingOps(); - var last = pendingOps.length - 1; - var stateController = _CoreManager2.default.getObjectStateController(); - for (var attr in newOps) { - var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); - stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); - } - - return this; - } - - /** - * Remove an attribute from the model. This is a noop if the attribute doesn't - * exist. - * @method unset - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'unset', - value: function (attr, options) { - options = options || {}; - options.unset = true; - return this.set(attr, null, options); - } - - /** - * Atomically increments the value of the given attribute the next time the - * object is saved. If no amount is specified, 1 is used by default. - * - * @method increment - * @param attr {String} The key. - * @param amount {Number} The amount to increment by (optional). - */ - - }, { - key: 'increment', - value: function (attr, amount) { - if (typeof amount === 'undefined') { - amount = 1; - } - if (typeof amount !== 'number') { - throw new Error('Cannot increment by a non-numeric amount.'); - } - return this.set(attr, new _ParseOp.IncrementOp(amount)); - } - - /** - * Atomically add an object to the end of the array associated with a given - * key. - * @method add - * @param attr {String} The key. - * @param item {} The item to add. - */ - - }, { - key: 'add', - value: function (attr, item) { - return this.set(attr, new _ParseOp.AddOp([item])); - } - - /** - * Atomically add an object to the array associated with a given key, only - * if it is not already present in the array. The position of the insert is - * not guaranteed. - * - * @method addUnique - * @param attr {String} The key. - * @param item {} The object to add. - */ - - }, { - key: 'addUnique', - value: function (attr, item) { - return this.set(attr, new _ParseOp.AddUniqueOp([item])); - } - - /** - * Atomically remove all instances of an object from the array associated - * with a given key. - * - * @method remove - * @param attr {String} The key. - * @param item {} The object to remove. - */ - - }, { - key: 'remove', - value: function (attr, item) { - return this.set(attr, new _ParseOp.RemoveOp([item])); - } - - /** - * Returns an instance of a subclass of Parse.Op describing what kind of - * modification has been performed on this field since the last time it was - * saved. For example, after calling object.increment("x"), calling - * object.op("x") would return an instance of Parse.Op.Increment. - * - * @method op - * @param attr {String} The key. - * @returns {Parse.Op} The operation, or undefined if none. - */ - - }, { - key: 'op', - value: function (attr) { - var pending = this._getPendingOps(); - for (var i = pending.length; i--;) { - if (pending[i][attr]) { - return pending[i][attr]; - } - } - } - - /** - * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() - * @method clone - * @return {Parse.Object} - */ - - }, { - key: 'clone', - value: function () { - var clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - var attributes = this.attributes; - if (typeof this.constructor.readOnlyAttributes === 'function') { - var readonly = this.constructor.readOnlyAttributes() || []; - // Attributes are frozen, so we have to rebuild an object, - // rather than delete readonly keys - var copy = {}; - for (var a in attributes) { - if (readonly.indexOf(a) < 0) { - copy[a] = attributes[a]; - } - } - attributes = copy; - } - if (clone.set) { - clone.set(attributes); - } - return clone; - } - - /** - * Creates a new instance of this object. Not to be confused with clone() - * @method newInstance - * @return {Parse.Object} - */ - - }, { - key: 'newInstance', - value: function () { - var clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - clone.id = this.id; - if (singleInstance) { - // Just return an object with the right id - return clone; - } - - var stateController = _CoreManager2.default.getObjectStateController(); - if (stateController) { - stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); - } - return clone; - } - - /** - * Returns true if this object has never been saved to Parse. - * @method isNew - * @return {Boolean} - */ - - }, { - key: 'isNew', - value: function () { - return !this.id; - } - - /** - * Returns true if this object was created by the Parse server when the - * object might have already been there (e.g. in the case of a Facebook - * login) - * @method existed - * @return {Boolean} - */ - - }, { - key: 'existed', - value: function () { - if (!this.id) { - return false; - } - var stateController = _CoreManager2.default.getObjectStateController(); - var state = stateController.getState(this._getStateIdentifier()); - if (state) { - return state.existed; - } - return false; - } - - /** - * Checks if the model is currently in a valid state. - * @method isValid - * @return {Boolean} - */ - - }, { - key: 'isValid', - value: function () { - return !this.validate(this.attributes); - } - - /** - * You should not call this function directly unless you subclass - * Parse.Object, in which case you can override this method - * to provide additional validation on set and - * save. Your implementation should return - * - * @method validate - * @param {Object} attrs The current data to validate. - * @return {} False if the data is valid. An error object otherwise. - * @see Parse.Object#set - */ - - }, { - key: 'validate', - value: function (attrs) { - if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof _ParseACL2.default)) { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'ACL must be a Parse ACL.'); - } - for (var key in attrs) { - if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { - return new _ParseError2.default(_ParseError2.default.INVALID_KEY_NAME); - } - } - return false; - } - - /** - * Returns the ACL for this object. - * @method getACL - * @returns {Parse.ACL} An instance of Parse.ACL. - * @see Parse.Object#get - */ - - }, { - key: 'getACL', - value: function () { - var acl = this.get('ACL'); - if (acl instanceof _ParseACL2.default) { - return acl; - } - return null; - } - - /** - * Sets the ACL to be used for this object. - * @method setACL - * @param {Parse.ACL} acl An instance of Parse.ACL. - * @param {Object} options Optional Backbone-like options object to be - * passed in to set. - * @return {Boolean} Whether the set passed validation. - * @see Parse.Object#set - */ - - }, { - key: 'setACL', - value: function (acl, options) { - return this.set('ACL', acl, options); - } - - /** - * Clears any changes to this object made since the last call to save() - * @method revert - */ - - }, { - key: 'revert', - value: function () { - this._clearPendingOps(); - } - - /** - * Clears all attributes on a model - * @method clear - */ - - }, { - key: 'clear', - value: function () { - var attributes = this.attributes; - var erasable = {}; - var readonly = ['createdAt', 'updatedAt']; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var attr in attributes) { - if (readonly.indexOf(attr) < 0) { - erasable[attr] = true; - } - } - return this.set(erasable, { unset: true }); - } - - /** - * Fetch the model from the server. If the server's representation of the - * model differs from its current attributes, they will be overriden. - * - * @method fetch - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                        - *
                      • success: A Backbone-style success callback. - *
                      • error: An Backbone-style error callback. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * @return {Parse.Promise} A promise that is fulfilled when the fetch - * completes. - */ - - }, { - key: 'fetch', - value: function (options) { - options = options || {}; - var fetchOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - fetchOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - fetchOptions.sessionToken = options.sessionToken; - } - var controller = _CoreManager2.default.getObjectController(); - return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); - } - - /** - * Set a hash of model attributes, and save the model to the server. - * updatedAt will be updated when the request returns. - * You can either call it as:
                      -     *   object.save();
                      - * or
                      -     *   object.save(null, options);
                      - * or
                      -     *   object.save(attrs, options);
                      - * or
                      -     *   object.save(key, value, options);
                      - * - * For example,
                      -     *   gameTurn.save({
                      -     *     player: "Jake Cutter",
                      -     *     diceRoll: 2
                      -     *   }, {
                      -     *     success: function(gameTurnAgain) {
                      -     *       // The save was successful.
                      -     *     },
                      -     *     error: function(gameTurnAgain, error) {
                      -     *       // The save failed.  Error is an instance of Parse.Error.
                      -     *     }
                      -     *   });
                      - * or with promises:
                      -     *   gameTurn.save({
                      -     *     player: "Jake Cutter",
                      -     *     diceRoll: 2
                      -     *   }).then(function(gameTurnAgain) {
                      -     *     // The save was successful.
                      -     *   }, function(error) {
                      -     *     // The save failed.  Error is an instance of Parse.Error.
                      -     *   });
                      - * - * @method save - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                        - *
                      • success: A Backbone-style success callback. - *
                      • error: An Backbone-style error callback. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * @return {Parse.Promise} A promise that is fulfilled when the save - * completes. - */ - - }, { - key: 'save', - value: function (arg1, arg2, arg3) { - var _this = this; - - var attrs; - var options; - if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object' || typeof arg1 === 'undefined') { - attrs = arg1; - if ((typeof arg2 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg2)) === 'object') { - options = arg2; - } - } else { - attrs = {}; - attrs[arg1] = arg2; - options = arg3; - } - - // Support save({ success: function() {}, error: function() {} }) - if (!options && attrs) { - options = {}; - if (typeof attrs.success === 'function') { - options.success = attrs.success; - delete attrs.success; - } - if (typeof attrs.error === 'function') { - options.error = attrs.error; - delete attrs.error; - } - } - - if (attrs) { - var validation = this.validate(attrs); - if (validation) { - if (options && typeof options.error === 'function') { - options.error(this, validation); - } - return _ParsePromise2.default.error(validation); - } - this.set(attrs, options); - } - - options = options || {}; - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = !!options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { - saveOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getObjectController(); - var unsaved = (0, _unsavedChildren2.default)(this); - return controller.save(unsaved, saveOptions).then(function () { - return controller.save(_this, saveOptions); - })._thenRunCallbacks(options, this); - } - - /** - * Destroy this model on the server if it was already persisted. - * If `wait: true` is passed, waits for the server to respond - * before removal. - * - * @method destroy - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                        - *
                      • success: A Backbone-style success callback - *
                      • error: An Backbone-style error callback. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * @return {Parse.Promise} A promise that is fulfilled when the destroy - * completes. - */ - - }, { - key: 'destroy', - value: function (options) { - options = options || {}; - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - if (!this.id) { - return _ParsePromise2.default.as()._thenRunCallbacks(options); - } - return _CoreManager2.default.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); - } - - /** Static methods **/ - - }, { - key: 'attributes', - get: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return (0, _freeze2.default)(stateController.estimateAttributes(this._getStateIdentifier())); - } - - /** - * The first time this object was saved on the server. - * @property createdAt - * @type Date - */ - - }, { - key: 'createdAt', - get: function () { - return this._getServerData().createdAt; - } - - /** - * The last time this object was updated on the server. - * @property updatedAt - * @type Date - */ - - }, { - key: 'updatedAt', - get: function () { - return this._getServerData().updatedAt; - } - }], [{ - key: '_clearAllState', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.clearAllState(); - } - - /** - * Fetches the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                      -     *   Parse.Object.fetchAll([object1, object2, ...], {
                      -     *     success: function(list) {
                      -     *       // All the objects were fetched.
                      -     *     },
                      -     *     error: function(error) {
                      -     *       // An error occurred while fetching one of the objects.
                      -     *     },
                      -     *   });
                      -     * 
                      - * - * @method fetchAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                        - *
                      • success: A Backbone-style success callback. - *
                      • error: An Backbone-style error callback. - *
                      - */ - - }, { - key: 'fetchAll', - value: function (list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); - } - - /** - * Fetches the given list of Parse.Object if needed. - * If any error is encountered, stops and calls the error handler. - * - *
                      -     *   Parse.Object.fetchAllIfNeeded([object1, ...], {
                      -     *     success: function(list) {
                      -     *       // Objects were fetched and updated.
                      -     *     },
                      -     *     error: function(error) {
                      -     *       // An error occurred while fetching one of the objects.
                      -     *     },
                      -     *   });
                      -     * 
                      - * - * @method fetchAllIfNeeded - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                        - *
                      • success: A Backbone-style success callback. - *
                      • error: An Backbone-style error callback. - *
                      - */ - - }, { - key: 'fetchAllIfNeeded', - value: function (list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); - } - - /** - * Destroy the given list of models on the server if it was already persisted. - * - *

                      Unlike saveAll, if an error occurs while deleting an individual model, - * this method will continue trying to delete the rest of the models if - * possible, except in the case of a fatal error like a connection error. - * - *

                      In particular, the Parse.Error object returned in the case of error may - * be one of two types: - * - *

                        - *
                      • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an - * array of other Parse.Error objects. Each error object in this array - * has an "object" property that references the object that could not be - * deleted (for instance, because that object could not be found).
                      • - *
                      • A non-aggregate Parse.Error. This indicates a serious error that - * caused the delete operation to be aborted partway through (for - * instance, a connection failure in the middle of the delete).
                      • - *
                      - * - *
                      -     *   Parse.Object.destroyAll([object1, object2, ...], {
                      -     *     success: function() {
                      -     *       // All the objects were deleted.
                      -     *     },
                      -     *     error: function(error) {
                      -     *       // An error occurred while deleting one or more of the objects.
                      -     *       // If this is an aggregate error, then we can inspect each error
                      -     *       // object individually to determine the reason why a particular
                      -     *       // object was not deleted.
                      -     *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
                      -     *         for (var i = 0; i < error.errors.length; i++) {
                      -     *           console.log("Couldn't delete " + error.errors[i].object.id +
                      -     *             "due to " + error.errors[i].message);
                      -     *         }
                      -     *       } else {
                      -     *         console.log("Delete aborted because of " + error.message);
                      -     *       }
                      -     *     },
                      -     *   });
                      -     * 
                      - * - * @method destroyAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                        - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * @return {Parse.Promise} A promise that is fulfilled when the destroyAll - * completes. - */ - - }, { - key: 'destroyAll', - value: function (list, options) { - var options = options || {}; - - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); - } - - /** - * Saves the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                      -     *   Parse.Object.saveAll([object1, object2, ...], {
                      -     *     success: function(list) {
                      -     *       // All the objects were saved.
                      -     *     },
                      -     *     error: function(error) {
                      -     *       // An error occurred while saving one of the objects.
                      -     *     },
                      -     *   });
                      -     * 
                      - * - * @method saveAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                        - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - */ - - }, { - key: 'saveAll', - value: function (list, options) { - var options = options || {}; - - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - saveOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); - } - - /** - * Creates a reference to a subclass of Parse.Object with the given id. This - * does not exist on Parse.Object, only on subclasses. - * - *

                      A shortcut for:

                      -     *  var Foo = Parse.Object.extend("Foo");
                      -     *  var pointerToFoo = new Foo();
                      -     *  pointerToFoo.id = "myObjectId";
                      -     * 
                      - * - * @method createWithoutData - * @param {String} id The ID of the object to create a reference to. - * @static - * @return {Parse.Object} A Parse.Object reference. - */ - - }, { - key: 'createWithoutData', - value: function (id) { - var obj = new this(); - obj.id = id; - return obj; - } - - /** - * Creates a new instance of a Parse Object from a JSON representation. - * @method fromJSON - * @param {Object} json The JSON map of the Object's data - * @param {boolean} override In single instance mode, all old server data - * is overwritten if this is set to true - * @static - * @return {Parse.Object} A Parse.Object reference - */ - - }, { - key: 'fromJSON', - value: function (json, override) { - if (!json.className) { - throw new Error('Cannot create an object without a className'); - } - var constructor = classMap[json.className]; - var o = constructor ? new constructor() : new ParseObject(json.className); - var otherAttributes = {}; - for (var attr in json) { - if (attr !== 'className' && attr !== '__type') { - otherAttributes[attr] = json[attr]; - } - } - if (override) { - // id needs to be set before clearServerData can work - if (otherAttributes.objectId) { - o.id = otherAttributes.objectId; - } - var preserved = null; - if (typeof o._preserveFieldsOnFetch === 'function') { - preserved = o._preserveFieldsOnFetch(); - } - o._clearServerData(); - if (preserved) { - o._finishFetch(preserved); - } - } - o._finishFetch(otherAttributes); - if (json.objectId) { - o._setExisted(true); - } - return o; - } - - /** - * Registers a subclass of Parse.Object with a specific class name. - * When objects of that class are retrieved from a query, they will be - * instantiated with this subclass. - * This is only necessary when using ES6 subclassing. - * @method registerSubclass - * @param {String} className The class name of the subclass - * @param {Class} constructor The subclass - */ - - }, { - key: 'registerSubclass', - value: function (className, constructor) { - if (typeof className !== 'string') { - throw new TypeError('The first argument must be a valid class name.'); - } - if (typeof constructor === 'undefined') { - throw new TypeError('You must supply a subclass constructor.'); - } - if (typeof constructor !== 'function') { - throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); - } - classMap[className] = constructor; - if (!constructor.className) { - constructor.className = className; - } - } - - /** - * Creates a new subclass of Parse.Object for the given Parse class name. - * - *

                      Every extension of a Parse class will inherit from the most recent - * previous extension of that class. When a Parse.Object is automatically - * created by parsing JSON, it will use the most recent extension of that - * class.

                      - * - *

                      You should call either:

                      -     *     var MyClass = Parse.Object.extend("MyClass", {
                      -     *         Instance methods,
                      -     *         initialize: function(attrs, options) {
                      -     *             this.someInstanceProperty = [],
                      -     *             Other instance properties
                      -     *         }
                      -     *     }, {
                      -     *         Class properties
                      -     *     });
                      - * or, for Backbone compatibility:
                      -     *     var MyClass = Parse.Object.extend({
                      -     *         className: "MyClass",
                      -     *         Instance methods,
                      -     *         initialize: function(attrs, options) {
                      -     *             this.someInstanceProperty = [],
                      -     *             Other instance properties
                      -     *         }
                      -     *     }, {
                      -     *         Class properties
                      -     *     });

                      - * - * @method extend - * @param {String} className The name of the Parse class backing this model. - * @param {Object} protoProps Instance properties to add to instances of the - * class returned from this method. - * @param {Object} classProps Class properties to add the class returned from - * this method. - * @return {Class} A new subclass of Parse.Object. - */ - - }, { - key: 'extend', - value: function (className, protoProps, classProps) { - if (typeof className !== 'string') { - if (className && typeof className.className === 'string') { - return ParseObject.extend(className.className, className, protoProps); - } else { - throw new Error('Parse.Object.extend\'s first argument should be the className.'); - } - } - var adjustedClassName = className; - - if (adjustedClassName === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { - adjustedClassName = '_User'; - } - - var parentProto = ParseObject.prototype; - if (this.hasOwnProperty('__super__') && this.__super__) { - parentProto = this.prototype; - } else if (classMap[adjustedClassName]) { - parentProto = classMap[adjustedClassName].prototype; - } - var ParseObjectSubclass = function (attributes, options) { - this.className = adjustedClassName; - this._objCount = objectCount++; - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!this.set(attributes || {}, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - }; - ParseObjectSubclass.className = adjustedClassName; - ParseObjectSubclass.__super__ = parentProto; - - ParseObjectSubclass.prototype = (0, _create2.default)(parentProto, { - constructor: { - value: ParseObjectSubclass, - enumerable: false, - writable: true, - configurable: true - } - }); - - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseObjectSubclass.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseObjectSubclass, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - ParseObjectSubclass.extend = function (name, protoProps, classProps) { - if (typeof name === 'string') { - return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); - } - return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); - }; - ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; - - classMap[adjustedClassName] = ParseObjectSubclass; - return ParseObjectSubclass; - } - - /** - * Enable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * This is disabled by default in server environments, since it can lead to - * security issues. - * @method enableSingleInstance - */ - - }, { - key: 'enableSingleInstance', - value: function () { - singleInstance = true; - _CoreManager2.default.setObjectStateController(SingleInstanceStateController); - } - - /** - * Disable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * When disabled, you can have two instances of the same object in memory - * without them sharing attributes. - * @method disableSingleInstance - */ - - }, { - key: 'disableSingleInstance', - value: function () { - singleInstance = false; - _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); - } - }]); - return ParseObject; -}(); - -exports.default = ParseObject; - -var DefaultController = { - fetch: function (target, forceFetch, options) { - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - var objs = []; - var ids = []; - var className = null; - var results = []; - var error = null; - target.forEach(function (el, i) { - if (error) { - return; - } - if (!className) { - className = el.className; - } - if (className !== el.className) { - error = new _ParseError2.default(_ParseError2.default.INVALID_CLASS_NAME, 'All objects should be of the same class'); - } - if (!el.id) { - error = new _ParseError2.default(_ParseError2.default.MISSING_OBJECT_ID, 'All objects must have an ID'); - } - if (forceFetch || (0, _keys2.default)(el._getServerData()).length === 0) { - ids.push(el.id); - objs.push(el); - } - results.push(el); - }); - if (error) { - return _ParsePromise2.default.error(error); - } - var query = new _ParseQuery2.default(className); - query.containedIn('objectId', ids); - query._limit = ids.length; - return query.find(options).then(function (objects) { - var idMap = {}; - objects.forEach(function (o) { - idMap[o.id] = o; - }); - for (var i = 0; i < objs.length; i++) { - var obj = objs[i]; - if (!obj || !obj.id || !idMap[obj.id]) { - if (forceFetch) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); - } - } - } - if (!singleInstance) { - // If single instance objects are disabled, we need to replace the - for (var i = 0; i < results.length; i++) { - var obj = results[i]; - if (obj && obj.id && idMap[obj.id]) { - var id = obj.id; - obj._finishFetch(idMap[id].toJSON()); - results[i] = idMap[id]; - } - } - } - return _ParsePromise2.default.as(results); - }); - } else { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function (response, status, xhr) { - if (target instanceof ParseObject) { - target._clearPendingOps(); - target._clearServerData(); - target._finishFetch(response); - } - return target; - }); - } - }, - destroy: function (target, options) { - var RESTController = _CoreManager2.default.getRESTController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - var batches = [[]]; - target.forEach(function (obj) { - if (!obj.id) { - return; - } - batches[batches.length - 1].push(obj); - if (batches[batches.length - 1].length >= 20) { - batches.push([]); - } - }); - if (batches[batches.length - 1].length === 0) { - // If the last batch is empty, remove it - batches.pop(); - } - var deleteCompleted = _ParsePromise2.default.as(); - var errors = []; - batches.forEach(function (batch) { - deleteCompleted = deleteCompleted.then(function () { - return RESTController.request('POST', 'batch', { - requests: batch.map(function (obj) { - return { - method: 'DELETE', - path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), - body: {} - }; - }) - }, options).then(function (results) { - for (var i = 0; i < results.length; i++) { - if (results[i] && results[i].hasOwnProperty('error')) { - var err = new _ParseError2.default(results[i].error.code, results[i].error.error); - err.object = batch[i]; - errors.push(err); - } - } - }); - }); - }); - return deleteCompleted.then(function () { - if (errors.length) { - var aggregate = new _ParseError2.default(_ParseError2.default.AGGREGATE_ERROR); - aggregate.errors = errors; - return _ParsePromise2.default.error(aggregate); - } - return _ParsePromise2.default.as(target); - }); - } else if (target instanceof ParseObject) { - return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function () { - return _ParsePromise2.default.as(target); - }); - } - return _ParsePromise2.default.as(target); - }, - save: function (target, options) { - var RESTController = _CoreManager2.default.getRESTController(); - var stateController = _CoreManager2.default.getObjectStateController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - - var unsaved = target.concat(); - for (var i = 0; i < target.length; i++) { - if (target[i] instanceof ParseObject) { - unsaved = unsaved.concat((0, _unsavedChildren2.default)(target[i], true)); - } - } - unsaved = (0, _unique2.default)(unsaved); - - var filesSaved = _ParsePromise2.default.as(); - var pending = []; - unsaved.forEach(function (el) { - if (el instanceof _ParseFile2.default) { - filesSaved = filesSaved.then(function () { - return el.save(); - }); - } else if (el instanceof ParseObject) { - pending.push(el); - } - }); - - return filesSaved.then(function () { - var objectError = null; - return _ParsePromise2.default._continueWhile(function () { - return pending.length > 0; - }, function () { - var batch = []; - var nextPending = []; - pending.forEach(function (el) { - if (batch.length < 20 && (0, _canBeSerialized2.default)(el)) { - batch.push(el); - } else { - nextPending.push(el); - } - }); - pending = nextPending; - if (batch.length < 1) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); - } - - // Queue up tasks for each object in the batch. - // When every task is ready, the API request will execute - var batchReturned = new _ParsePromise2.default(); - var batchReady = []; - var batchTasks = []; - batch.forEach(function (obj, index) { - var ready = new _ParsePromise2.default(); - batchReady.push(ready); - - stateController.pushPendingState(obj._getStateIdentifier()); - batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { - ready.resolve(); - return batchReturned.then(function (responses, status) { - if (responses[index].hasOwnProperty('success')) { - obj._handleSaveResponse(responses[index].success, status); - } else { - if (!objectError && responses[index].hasOwnProperty('error')) { - var serverError = responses[index].error; - objectError = new _ParseError2.default(serverError.code, serverError.error); - // Cancel the rest of the save - pending = []; - } - obj._handleSaveError(); - } - }); - })); - }); - - _ParsePromise2.default.when(batchReady).then(function () { - // Kick off the batch request - return RESTController.request('POST', 'batch', { - requests: batch.map(function (obj) { - var params = obj._getSaveParams(); - params.path = getServerUrlPath() + params.path; - return params; - }) - }, options); - }).then(function (response, status, xhr) { - batchReturned.resolve(response, status); - }); - - return _ParsePromise2.default.when(batchTasks); - }).then(function () { - if (objectError) { - return _ParsePromise2.default.error(objectError); - } - return _ParsePromise2.default.as(target); - }); - }); - } else if (target instanceof ParseObject) { - // copying target lets Flow guarantee the pointer isn't modified elsewhere - var targetCopy = target; - var task = function () { - var params = targetCopy._getSaveParams(); - return RESTController.request(params.method, params.path, params.body, options).then(function (response, status) { - targetCopy._handleSaveResponse(response, status); - }, function (error) { - targetCopy._handleSaveError(); - return _ParsePromise2.default.error(error); - }); - }; - - stateController.pushPendingState(target._getStateIdentifier()); - return stateController.enqueueTask(target._getStateIdentifier(), task).then(function () { - return target; - }, function (error) { - return _ParsePromise2.default.error(error); - }); - } - return _ParsePromise2.default.as(); - } -}; - -_CoreManager2.default.setObjectController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseOp.js b/lib/browser/ParseOp.js deleted file mode 100644 index 1eba19303..000000000 --- a/lib/browser/ParseOp.js +++ /dev/null @@ -1,579 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.RelationOp = exports.RemoveOp = exports.AddUniqueOp = exports.AddOp = exports.IncrementOp = exports.UnsetOp = exports.SetOp = exports.Op = undefined; - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -exports.opFromJSON = opFromJSON; - -var _arrayContainsObject = require('./arrayContainsObject'); - -var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _unique = require('./unique'); - -var _unique2 = _interopRequireDefault(_unique); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function opFromJSON(json) { - if (!json || !json.__op) { - return null; - } - switch (json.__op) { - case 'Delete': - return new UnsetOp(); - case 'Increment': - return new IncrementOp(json.amount); - case 'Add': - return new AddOp((0, _decode2.default)(json.objects)); - case 'AddUnique': - return new AddUniqueOp((0, _decode2.default)(json.objects)); - case 'Remove': - return new RemoveOp((0, _decode2.default)(json.objects)); - case 'AddRelation': - var toAdd = (0, _decode2.default)(json.objects); - if (!Array.isArray(toAdd)) { - return new RelationOp([], []); - } - return new RelationOp(toAdd, []); - case 'RemoveRelation': - var toRemove = (0, _decode2.default)(json.objects); - if (!Array.isArray(toRemove)) { - return new RelationOp([], []); - } - return new RelationOp([], toRemove); - case 'Batch': - var toAdd = []; - var toRemove = []; - for (var i = 0; i < json.ops.length; i++) { - if (json.ops[i].__op === 'AddRelation') { - toAdd = toAdd.concat((0, _decode2.default)(json.ops[i].objects)); - } else if (json.ops[i].__op === 'RemoveRelation') { - toRemove = toRemove.concat((0, _decode2.default)(json.ops[i].objects)); - } - } - return new RelationOp(toAdd, toRemove); - } - return null; -} - -var Op = exports.Op = function () { - function Op() { - (0, _classCallCheck3.default)(this, Op); - } - - (0, _createClass3.default)(Op, [{ - key: 'applyTo', - - // Empty parent class - value: function (value) {} - }, { - key: 'mergeWith', - value: function (previous) {} - }, { - key: 'toJSON', - value: function () {} - }]); - return Op; -}(); - -var SetOp = exports.SetOp = function (_Op) { - (0, _inherits3.default)(SetOp, _Op); - - function SetOp(value) { - (0, _classCallCheck3.default)(this, SetOp); - - var _this = (0, _possibleConstructorReturn3.default)(this, (SetOp.__proto__ || (0, _getPrototypeOf2.default)(SetOp)).call(this)); - - _this._value = value; - return _this; - } - - (0, _createClass3.default)(SetOp, [{ - key: 'applyTo', - value: function (value) { - return this._value; - } - }, { - key: 'mergeWith', - value: function (previous) { - return new SetOp(this._value); - } - }, { - key: 'toJSON', - value: function () { - return (0, _encode2.default)(this._value, false, true); - } - }]); - return SetOp; -}(Op); - -var UnsetOp = exports.UnsetOp = function (_Op2) { - (0, _inherits3.default)(UnsetOp, _Op2); - - function UnsetOp() { - (0, _classCallCheck3.default)(this, UnsetOp); - return (0, _possibleConstructorReturn3.default)(this, (UnsetOp.__proto__ || (0, _getPrototypeOf2.default)(UnsetOp)).apply(this, arguments)); - } - - (0, _createClass3.default)(UnsetOp, [{ - key: 'applyTo', - value: function (value) { - return undefined; - } - }, { - key: 'mergeWith', - value: function (previous) { - return new UnsetOp(); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Delete' }; - } - }]); - return UnsetOp; -}(Op); - -var IncrementOp = exports.IncrementOp = function (_Op3) { - (0, _inherits3.default)(IncrementOp, _Op3); - - function IncrementOp(amount) { - (0, _classCallCheck3.default)(this, IncrementOp); - - var _this3 = (0, _possibleConstructorReturn3.default)(this, (IncrementOp.__proto__ || (0, _getPrototypeOf2.default)(IncrementOp)).call(this)); - - if (typeof amount !== 'number') { - throw new TypeError('Increment Op must be initialized with a numeric amount.'); - } - _this3._amount = amount; - return _this3; - } - - (0, _createClass3.default)(IncrementOp, [{ - key: 'applyTo', - value: function (value) { - if (typeof value === 'undefined') { - return this._amount; - } - if (typeof value !== 'number') { - throw new TypeError('Cannot increment a non-numeric value.'); - } - return this._amount + value; - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._amount); - } - if (previous instanceof IncrementOp) { - return new IncrementOp(this.applyTo(previous._amount)); - } - throw new Error('Cannot merge Increment Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Increment', amount: this._amount }; - } - }]); - return IncrementOp; -}(Op); - -var AddOp = exports.AddOp = function (_Op4) { - (0, _inherits3.default)(AddOp, _Op4); - - function AddOp(value) { - (0, _classCallCheck3.default)(this, AddOp); - - var _this4 = (0, _possibleConstructorReturn3.default)(this, (AddOp.__proto__ || (0, _getPrototypeOf2.default)(AddOp)).call(this)); - - _this4._value = Array.isArray(value) ? value : [value]; - return _this4; - } - - (0, _createClass3.default)(AddOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return this._value; - } - if (Array.isArray(value)) { - return value.concat(this._value); - } - throw new Error('Cannot add elements to a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddOp) { - return new AddOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge Add Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Add', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return AddOp; -}(Op); - -var AddUniqueOp = exports.AddUniqueOp = function (_Op5) { - (0, _inherits3.default)(AddUniqueOp, _Op5); - - function AddUniqueOp(value) { - (0, _classCallCheck3.default)(this, AddUniqueOp); - - var _this5 = (0, _possibleConstructorReturn3.default)(this, (AddUniqueOp.__proto__ || (0, _getPrototypeOf2.default)(AddUniqueOp)).call(this)); - - _this5._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); - return _this5; - } - - (0, _createClass3.default)(AddUniqueOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return this._value || []; - } - if (Array.isArray(value)) { - // copying value lets Flow guarantee the pointer isn't modified elsewhere - var valueCopy = value; - var toAdd = []; - this._value.forEach(function (v) { - if (v instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(valueCopy, v)) { - toAdd.push(v); - } - } else { - if (valueCopy.indexOf(v) < 0) { - toAdd.push(v); - } - } - }); - return value.concat(toAdd); - } - throw new Error('Cannot add elements to a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddUniqueOp) { - return new AddUniqueOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge AddUnique Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'AddUnique', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return AddUniqueOp; -}(Op); - -var RemoveOp = exports.RemoveOp = function (_Op6) { - (0, _inherits3.default)(RemoveOp, _Op6); - - function RemoveOp(value) { - (0, _classCallCheck3.default)(this, RemoveOp); - - var _this6 = (0, _possibleConstructorReturn3.default)(this, (RemoveOp.__proto__ || (0, _getPrototypeOf2.default)(RemoveOp)).call(this)); - - _this6._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); - return _this6; - } - - (0, _createClass3.default)(RemoveOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return []; - } - if (Array.isArray(value)) { - var i = value.indexOf(this._value); - var removed = value.concat([]); - for (var i = 0; i < this._value.length; i++) { - var index = removed.indexOf(this._value[i]); - while (index > -1) { - removed.splice(index, 1); - index = removed.indexOf(this._value[i]); - } - if (this._value[i] instanceof _ParseObject2.default && this._value[i].id) { - for (var j = 0; j < removed.length; j++) { - if (removed[j] instanceof _ParseObject2.default && this._value[i].id === removed[j].id) { - removed.splice(j, 1); - j--; - } - } - } - } - return removed; - } - throw new Error('Cannot remove elements from a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new UnsetOp(); - } - if (previous instanceof RemoveOp) { - var uniques = previous._value.concat([]); - for (var i = 0; i < this._value.length; i++) { - if (this._value[i] instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(uniques, this._value[i])) { - uniques.push(this._value[i]); - } - } else { - if (uniques.indexOf(this._value[i]) < 0) { - uniques.push(this._value[i]); - } - } - } - return new RemoveOp(uniques); - } - throw new Error('Cannot merge Remove Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Remove', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return RemoveOp; -}(Op); - -var RelationOp = exports.RelationOp = function (_Op7) { - (0, _inherits3.default)(RelationOp, _Op7); - - function RelationOp(adds, removes) { - (0, _classCallCheck3.default)(this, RelationOp); - - var _this7 = (0, _possibleConstructorReturn3.default)(this, (RelationOp.__proto__ || (0, _getPrototypeOf2.default)(RelationOp)).call(this)); - - _this7._targetClassName = null; - - if (Array.isArray(adds)) { - _this7.relationsToAdd = (0, _unique2.default)(adds.map(_this7._extractId, _this7)); - } - - if (Array.isArray(removes)) { - _this7.relationsToRemove = (0, _unique2.default)(removes.map(_this7._extractId, _this7)); - } - return _this7; - } - - (0, _createClass3.default)(RelationOp, [{ - key: '_extractId', - value: function (obj) { - if (typeof obj === 'string') { - return obj; - } - if (!obj.id) { - throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); - } - if (!this._targetClassName) { - this._targetClassName = obj.className; - } - if (this._targetClassName !== obj.className) { - throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); - } - return obj.id; - } - }, { - key: 'applyTo', - value: function (value, object, key) { - if (!value) { - if (!object || !key) { - throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); - } - var parent = new _ParseObject2.default(object.className); - if (object.id && object.id.indexOf('local') === 0) { - parent._localId = object.id; - } else if (object.id) { - parent.id = object.id; - } - var relation = new _ParseRelation2.default(parent, key); - relation.targetClassName = this._targetClassName; - return relation; - } - if (value instanceof _ParseRelation2.default) { - if (this._targetClassName) { - if (value.targetClassName) { - if (this._targetClassName !== value.targetClassName) { - throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); - } - } else { - value.targetClassName = this._targetClassName; - } - } - return value; - } else { - throw new Error('Relation cannot be applied to a non-relation field'); - } - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } else if (previous instanceof UnsetOp) { - throw new Error('You cannot modify a relation after deleting it.'); - } else if (previous instanceof RelationOp) { - if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { - throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); - } - var newAdd = previous.relationsToAdd.concat([]); - this.relationsToRemove.forEach(function (r) { - var index = newAdd.indexOf(r); - if (index > -1) { - newAdd.splice(index, 1); - } - }); - this.relationsToAdd.forEach(function (r) { - var index = newAdd.indexOf(r); - if (index < 0) { - newAdd.push(r); - } - }); - - var newRemove = previous.relationsToRemove.concat([]); - this.relationsToAdd.forEach(function (r) { - var index = newRemove.indexOf(r); - if (index > -1) { - newRemove.splice(index, 1); - } - }); - this.relationsToRemove.forEach(function (r) { - var index = newRemove.indexOf(r); - if (index < 0) { - newRemove.push(r); - } - }); - - var newRelation = new RelationOp(newAdd, newRemove); - newRelation._targetClassName = this._targetClassName; - return newRelation; - } - throw new Error('Cannot merge Relation Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - var _this8 = this; - - var idToPointer = function (id) { - return { - __type: 'Pointer', - className: _this8._targetClassName, - objectId: id - }; - }; - - var adds = null; - var removes = null; - var pointers = null; - - if (this.relationsToAdd.length > 0) { - pointers = this.relationsToAdd.map(idToPointer); - adds = { __op: 'AddRelation', objects: pointers }; - } - if (this.relationsToRemove.length > 0) { - pointers = this.relationsToRemove.map(idToPointer); - removes = { __op: 'RemoveRelation', objects: pointers }; - } - - if (adds && removes) { - return { __op: 'Batch', ops: [adds, removes] }; - } - - return adds || removes || {}; - } - }]); - return RelationOp; -}(Op); \ No newline at end of file diff --git a/lib/browser/ParsePromise.js b/lib/browser/ParsePromise.js deleted file mode 100644 index a79b4afee..000000000 --- a/lib/browser/ParsePromise.js +++ /dev/null @@ -1,740 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getIterator2 = require('babel-runtime/core-js/get-iterator'); - -var _getIterator3 = _interopRequireDefault(_getIterator2); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var _isPromisesAPlusCompliant = true; - -/** - * A Promise is returned by async methods as a hook to provide callbacks to be - * called when the async task is fulfilled. - * - *

                      Typical usage would be like:

                      - *    query.find().then(function(results) {
                      - *      results[0].set("foo", "bar");
                      - *      return results[0].saveAsync();
                      - *    }).then(function(result) {
                      - *      console.log("Updated " + result.id);
                      - *    });
                      - * 

                      - * - * @class Parse.Promise - * @constructor - */ - -var ParsePromise = function () { - function ParsePromise(executor) { - (0, _classCallCheck3.default)(this, ParsePromise); - - this._resolved = false; - this._rejected = false; - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - - if (typeof executor === 'function') { - executor(this.resolve.bind(this), this.reject.bind(this)); - } - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method resolve - * @param {Object} result the result to pass to the callbacks. - */ - - (0, _createClass3.default)(ParsePromise, [{ - key: 'resolve', - value: function () { - if (this._resolved || this._rejected) { - throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._resolved = true; - - for (var _len = arguments.length, results = Array(_len), _key = 0; _key < _len; _key++) { - results[_key] = arguments[_key]; - } - - this._result = results; - for (var i = 0; i < this._resolvedCallbacks.length; i++) { - this._resolvedCallbacks[i].apply(this, results); - } - - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method reject - * @param {Object} error the error to pass to the callbacks. - */ - - }, { - key: 'reject', - value: function (error) { - if (this._resolved || this._rejected) { - throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._rejected = true; - this._error = error; - for (var i = 0; i < this._rejectedCallbacks.length; i++) { - this._rejectedCallbacks[i](error); - } - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Adds callbacks to be called when this promise is fulfilled. Returns a new - * Promise that will be fulfilled when the callback is complete. It allows - * chaining. If the callback itself returns a Promise, then the one returned - * by "then" will not be fulfilled until that one returned by the callback - * is fulfilled. - * @method then - * @param {Function} resolvedCallback Function that is called when this - * Promise is resolved. Once the callback is complete, then the Promise - * returned by "then" will also be fulfilled. - * @param {Function} rejectedCallback Function that is called when this - * Promise is rejected with an error. Once the callback is complete, then - * the promise returned by "then" with be resolved successfully. If - * rejectedCallback is null, or it returns a rejected Promise, then the - * Promise returned by "then" will be rejected with that error. - * @return {Parse.Promise} A new Promise that will be fulfilled after this - * Promise is fulfilled and either callback has completed. If the callback - * returned a Promise, then this Promise will not be fulfilled until that - * one is. - */ - - }, { - key: 'then', - value: function (resolvedCallback, rejectedCallback) { - var _this = this; - - var promise = new ParsePromise(); - - var wrappedResolvedCallback = function () { - for (var _len2 = arguments.length, results = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - results[_key2] = arguments[_key2]; - } - - if (typeof resolvedCallback === 'function') { - if (_isPromisesAPlusCompliant) { - try { - results = [resolvedCallback.apply(this, results)]; - } catch (e) { - results = [ParsePromise.error(e)]; - } - } else { - results = [resolvedCallback.apply(this, results)]; - } - } - if (results.length === 1 && ParsePromise.is(results[0])) { - results[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - promise.resolve.apply(promise, results); - } - }; - - var wrappedRejectedCallback = function (error) { - var result = []; - if (typeof rejectedCallback === 'function') { - if (_isPromisesAPlusCompliant) { - try { - result = [rejectedCallback(error)]; - } catch (e) { - result = [ParsePromise.error(e)]; - } - } else { - result = [rejectedCallback(error)]; - } - if (result.length === 1 && ParsePromise.is(result[0])) { - result[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - if (_isPromisesAPlusCompliant) { - promise.resolve.apply(promise, result); - } else { - promise.reject(result[0]); - } - } - } else { - promise.reject(error); - } - }; - - var runLater = function (fn) { - fn.call(); - }; - if (_isPromisesAPlusCompliant) { - if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { - runLater = function (fn) { - process.nextTick(fn); - }; - } else if (typeof setTimeout === 'function') { - runLater = function (fn) { - setTimeout(fn, 0); - }; - } - } - - if (this._resolved) { - runLater(function () { - wrappedResolvedCallback.apply(_this, _this._result); - }); - } else if (this._rejected) { - runLater(function () { - wrappedRejectedCallback(_this._error); - }); - } else { - this._resolvedCallbacks.push(wrappedResolvedCallback); - this._rejectedCallbacks.push(wrappedRejectedCallback); - } - - return promise; - } - - /** - * Add handlers to be called when the promise - * is either resolved or rejected - * @method always - */ - - }, { - key: 'always', - value: function (callback) { - return this.then(callback, callback); - } - - /** - * Add handlers to be called when the Promise object is resolved - * @method done - */ - - }, { - key: 'done', - value: function (callback) { - return this.then(callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * Alias for catch(). - * @method fail - */ - - }, { - key: 'fail', - value: function (callback) { - return this.then(null, callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * @method catch - */ - - }, { - key: 'catch', - value: function (callback) { - return this.then(null, callback); - } - - /** - * Run the given callbacks after this promise is fulfilled. - * @method _thenRunCallbacks - * @param optionsOrCallback {} A Backbone-style options callback, or a - * callback function. If this is an options object and contains a "model" - * attributes, that will be passed to error callbacks as the first argument. - * @param model {} If truthy, this will be passed as the first result of - * error callbacks. This is for Backbone-compatability. - * @return {Parse.Promise} A promise that will be resolved after the - * callbacks are run, with the same result as this. - */ - - }, { - key: '_thenRunCallbacks', - value: function (optionsOrCallback, model) { - var options = {}; - if (typeof optionsOrCallback === 'function') { - options.success = function (result) { - optionsOrCallback(result, null); - }; - options.error = function (error) { - optionsOrCallback(null, error); - }; - } else if ((typeof optionsOrCallback === 'undefined' ? 'undefined' : (0, _typeof3.default)(optionsOrCallback)) === 'object') { - if (typeof optionsOrCallback.success === 'function') { - options.success = optionsOrCallback.success; - } - if (typeof optionsOrCallback.error === 'function') { - options.error = optionsOrCallback.error; - } - } - - return this.then(function () { - for (var _len3 = arguments.length, results = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - results[_key3] = arguments[_key3]; - } - - if (options.success) { - options.success.apply(this, results); - } - return ParsePromise.as.apply(ParsePromise, arguments); - }, function (error) { - if (options.error) { - if (typeof model !== 'undefined') { - options.error(model, error); - } else { - options.error(error); - } - } - // By explicitly returning a rejected Promise, this will work with - // either jQuery or Promises/A+ semantics. - return ParsePromise.error(error); - }); - } - - /** - * Adds a callback function that should be called regardless of whether - * this promise failed or succeeded. The callback will be given either the - * array of results for its first argument, or the error as its second, - * depending on whether this Promise was rejected or resolved. Returns a - * new Promise, like "then" would. - * @method _continueWith - * @param {Function} continuation the callback. - */ - - }, { - key: '_continueWith', - value: function (continuation) { - return this.then(function () { - for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; - } - - return continuation(args, null); - }, function (error) { - return continuation(null, error); - }); - } - - /** - * Returns true iff the given object fulfils the Promise interface. - * @method is - * @param {Object} promise The object to test - * @static - * @return {Boolean} - */ - - }], [{ - key: 'is', - value: function (promise) { - return promise != null && typeof promise.then === 'function'; - } - - /** - * Returns a new promise that is resolved with a given value. - * @method as - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'as', - value: function () { - var promise = new ParsePromise(); - - for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - values[_key5] = arguments[_key5]; - } - - promise.resolve.apply(promise, values); - return promise; - } - - /** - * Returns a new promise that is resolved with a given value. - * If that value is a thenable Promise (has a .then() prototype - * method), the new promise will be chained to the end of the - * value. - * @method resolve - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'resolve', - value: function (value) { - return new ParsePromise(function (resolve, reject) { - if (ParsePromise.is(value)) { - value.then(resolve, reject); - } else { - resolve(value); - } - }); - } - - /** - * Returns a new promise that is rejected with a given error. - * @method error - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'error', - value: function () { - var promise = new ParsePromise(); - - for (var _len6 = arguments.length, errors = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - errors[_key6] = arguments[_key6]; - } - - promise.reject.apply(promise, errors); - return promise; - } - - /** - * Returns a new promise that is rejected with a given error. - * This is an alias for Parse.Promise.error, for compliance with - * the ES6 implementation. - * @method reject - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'reject', - value: function () { - for (var _len7 = arguments.length, errors = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - errors[_key7] = arguments[_key7]; - } - - return ParsePromise.error.apply(null, errors); - } - - /** - * Returns a new promise that is fulfilled when all of the input promises - * are resolved. If any promise in the list fails, then the returned promise - * will be rejected with an array containing the error from each promise. - * If they all succeed, then the returned promise will succeed, with the - * results being the results of all the input - * promises. For example:
                      -     *   var p1 = Parse.Promise.as(1);
                      -     *   var p2 = Parse.Promise.as(2);
                      -     *   var p3 = Parse.Promise.as(3);
                      -     *
                      -     *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
                      -     *     console.log(r1);  // prints 1
                      -     *     console.log(r2);  // prints 2
                      -     *     console.log(r3);  // prints 3
                      -     *   });
                      - * - * The input promises can also be specified as an array:
                      -     *   var promises = [p1, p2, p3];
                      -     *   Parse.Promise.when(promises).then(function(results) {
                      -     *     console.log(results);  // prints [1,2,3]
                      -     *   });
                      -     * 
                      - * @method when - * @param {Array} promises a list of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'when', - value: function (promises) { - var objects; - var arrayArgument = Array.isArray(promises); - if (arrayArgument) { - objects = promises; - } else { - objects = arguments; - } - - var total = objects.length; - var hadError = false; - var results = []; - var returnValue = arrayArgument ? [results] : results; - var errors = []; - results.length = objects.length; - errors.length = objects.length; - - if (total === 0) { - return ParsePromise.as.apply(this, returnValue); - } - - var promise = new ParsePromise(); - - var resolveOne = function () { - total--; - if (total <= 0) { - if (hadError) { - promise.reject(errors); - } else { - promise.resolve.apply(promise, returnValue); - } - } - }; - - var chain = function (object, index) { - if (ParsePromise.is(object)) { - object.then(function (result) { - results[index] = result; - resolveOne(); - }, function (error) { - errors[index] = error; - hadError = true; - resolveOne(); - }); - } else { - results[i] = object; - resolveOne(); - } - }; - for (var i = 0; i < objects.length; i++) { - chain(objects[i], i); - } - - return promise; - } - - /** - * Returns a new promise that is fulfilled when all of the promises in the - * iterable argument are resolved. If any promise in the list fails, then - * the returned promise will be immediately rejected with the reason that - * single promise rejected. If they all succeed, then the returned promise - * will succeed, with the results being the results of all the input - * promises. If the iterable provided is empty, the returned promise will - * be immediately resolved. - * - * For example:
                      -     *   var p1 = Parse.Promise.as(1);
                      -     *   var p2 = Parse.Promise.as(2);
                      -     *   var p3 = Parse.Promise.as(3);
                      -     *
                      -     *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
                      -     *     console.log(r1);  // prints 1
                      -     *     console.log(r2);  // prints 2
                      -     *     console.log(r3);  // prints 3
                      -     *   });
                      - * - * @method all - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'all', - value: function (promises) { - var total = 0; - var objects = []; - - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = (0, _getIterator3.default)(promises), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var p = _step.value; - - objects[total++] = p; - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - if (total === 0) { - return ParsePromise.as([]); - } - - var hadError = false; - var promise = new ParsePromise(); - var resolved = 0; - var results = []; - objects.forEach(function (object, i) { - if (ParsePromise.is(object)) { - object.then(function (result) { - if (hadError) { - return false; - } - results[i] = result; - resolved++; - if (resolved >= total) { - promise.resolve(results); - } - }, function (error) { - // Reject immediately - promise.reject(error); - hadError = true; - }); - } else { - results[i] = object; - resolved++; - if (!hadError && resolved >= total) { - promise.resolve(results); - } - } - }); - - return promise; - } - - /** - * Returns a new promise that is immediately fulfilled when any of the - * promises in the iterable argument are resolved or rejected. If the - * first promise to complete is resolved, the returned promise will be - * resolved with the same value. Likewise, if the first promise to - * complete is rejected, the returned promise will be rejected with the - * same reason. - * - * @method race - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'race', - value: function (promises) { - var completed = false; - var promise = new ParsePromise(); - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = (0, _getIterator3.default)(promises), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var p = _step2.value; - - if (ParsePromise.is(p)) { - p.then(function (result) { - if (completed) { - return; - } - completed = true; - promise.resolve(result); - }, function (error) { - if (completed) { - return; - } - completed = true; - promise.reject(error); - }); - } else if (!completed) { - completed = true; - promise.resolve(p); - } - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - return promise; - } - - /** - * Runs the given asyncFunction repeatedly, as long as the predicate - * function returns a truthy value. Stops repeating if asyncFunction returns - * a rejected promise. - * @method _continueWhile - * @param {Function} predicate should return false when ready to stop. - * @param {Function} asyncFunction should return a Promise. - * @static - */ - - }, { - key: '_continueWhile', - value: function (predicate, asyncFunction) { - if (predicate()) { - return asyncFunction().then(function () { - return ParsePromise._continueWhile(predicate, asyncFunction); - }); - } - return ParsePromise.as(); - } - }, { - key: 'isPromisesAPlusCompliant', - value: function () { - return _isPromisesAPlusCompliant; - } - }, { - key: 'enableAPlusCompliant', - value: function () { - _isPromisesAPlusCompliant = true; - } - }, { - key: 'disableAPlusCompliant', - value: function () { - _isPromisesAPlusCompliant = false; - } - }]); - return ParsePromise; -}(); - -exports.default = ParsePromise; \ No newline at end of file diff --git a/lib/browser/ParseQuery.js b/lib/browser/ParseQuery.js deleted file mode 100644 index 664f5a737..000000000 --- a/lib/browser/ParseQuery.js +++ /dev/null @@ -1,1340 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Converts a string into a regex that matches it. - * Surrounding with \Q .. \E does this, we just need to escape any \E's in - * the text separately. - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function quote(s) { - return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; -} - -/** - * Handles pre-populating the result data of a query with select fields, - * making sure that the data object contains keys for all objects that have - * been requested with a select, so that our cached state updates correctly. - */ -function handleSelectResult(data, select) { - var serverDataMask = {}; - - select.forEach(function (field) { - var hasSubObjectSelect = field.indexOf(".") !== -1; - if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { - // this field was selected, but is missing from the retrieved data - data[field] = undefined; - } else if (hasSubObjectSelect) { - // this field references a sub-object, - // so we need to walk down the path components - var pathComponents = field.split("."); - var obj = data; - var serverMask = serverDataMask; - - pathComponents.forEach(function (component, index, arr) { - // add keys if the expected data is missing - if (!obj[component]) { - obj[component] = index == arr.length - 1 ? undefined : {}; - } - obj = obj[component]; - - //add this path component to the server mask so we can fill it in later if needed - if (index < arr.length - 1) { - if (!serverMask[component]) { - serverMask[component] = {}; - } - } - }); - } - }); - - if ((0, _keys2.default)(serverDataMask).length > 0) { - var copyMissingDataWithMask = function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { - //copy missing elements at this level - if (copyThisLevel) { - for (var key in src) { - if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { - dest[key] = src[key]; - } - } - } - for (var key in mask) { - //traverse into objects as needed - copyMissingDataWithMask(src[key], dest[key], mask[key], true); - } - }; - - // When selecting from sub-objects, we don't want to blow away the missing - // information that we may have retrieved before. We've already added any - // missing selected keys to sub-objects, but we still need to add in the - // data for any previously retrieved sub-objects that were not selected. - - var serverData = _CoreManager2.default.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); - - copyMissingDataWithMask(serverData, data, serverDataMask, false); - } -} - -/** - * Creates a new parse Parse.Query for the given Parse.Object subclass. - * @class Parse.Query - * @constructor - * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. - * - *

                      Parse.Query defines a query that is used to fetch Parse.Objects. The - * most common use case is finding all objects that match a query through the - * find method. For example, this sample code fetches all objects - * of class MyClass. It calls a different function depending on - * whether the fetch succeeded or not. - * - *

                      - * var query = new Parse.Query(MyClass);
                      - * query.find({
                      - *   success: function(results) {
                      - *     // results is an array of Parse.Object.
                      - *   },
                      - *
                      - *   error: function(error) {
                      - *     // error is an instance of Parse.Error.
                      - *   }
                      - * });

                      - * - *

                      A Parse.Query can also be used to retrieve a single object whose id is - * known, through the get method. For example, this sample code fetches an - * object of class MyClass and id myId. It calls a - * different function depending on whether the fetch succeeded or not. - * - *

                      - * var query = new Parse.Query(MyClass);
                      - * query.get(myId, {
                      - *   success: function(object) {
                      - *     // object is an instance of Parse.Object.
                      - *   },
                      - *
                      - *   error: function(object, error) {
                      - *     // error is an instance of Parse.Error.
                      - *   }
                      - * });

                      - * - *

                      A Parse.Query can also be used to count the number of objects that match - * the query without retrieving all of those objects. For example, this - * sample code counts the number of objects of the class MyClass - *

                      - * var query = new Parse.Query(MyClass);
                      - * query.count({
                      - *   success: function(number) {
                      - *     // There are number instances of MyClass.
                      - *   },
                      - *
                      - *   error: function(error) {
                      - *     // error is an instance of Parse.Error.
                      - *   }
                      - * });

                      - */ - -var ParseQuery = function () { - function ParseQuery(objectClass) { - (0, _classCallCheck3.default)(this, ParseQuery); - - if (typeof objectClass === 'string') { - if (objectClass === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { - this.className = '_User'; - } else { - this.className = objectClass; - } - } else if (objectClass instanceof _ParseObject2.default) { - this.className = objectClass.className; - } else if (typeof objectClass === 'function') { - if (typeof objectClass.className === 'string') { - this.className = objectClass.className; - } else { - var obj = new objectClass(); - this.className = obj.className; - } - } else { - throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); - } - - this._where = {}; - this._include = []; - this._limit = -1; // negative limit is not sent in the server request - this._skip = 0; - this._extraOptions = {}; - } - - /** - * Adds constraint that at least one of the passed in queries matches. - * @method _orQuery - * @param {Array} queries - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - (0, _createClass3.default)(ParseQuery, [{ - key: '_orQuery', - value: function (queries) { - var queryJSON = queries.map(function (q) { - return q.toJSON().where; - }); - - this._where.$or = queryJSON; - return this; - } - - /** - * Helper for condition queries - */ - - }, { - key: '_addCondition', - value: function (key, condition, value) { - if (!this._where[key] || typeof this._where[key] === 'string') { - this._where[key] = {}; - } - this._where[key][condition] = (0, _encode2.default)(value, false, true); - return this; - } - - /** - * Converts string for regular expression at the beginning - */ - - }, { - key: '_regexStartWith', - value: function (string) { - return '^' + quote(string); - } - - /** - * Returns a JSON representation of this query. - * @method toJSON - * @return {Object} The JSON representation of the query. - */ - - }, { - key: 'toJSON', - value: function () { - var params = { - where: this._where - }; - - if (this._include.length) { - params.include = this._include.join(','); - } - if (this._select) { - params.keys = this._select.join(','); - } - if (this._limit >= 0) { - params.limit = this._limit; - } - if (this._skip > 0) { - params.skip = this._skip; - } - if (this._order) { - params.order = this._order.join(','); - } - for (var key in this._extraOptions) { - params[key] = this._extraOptions[key]; - } - - return params; - } - - /** - * Constructs a Parse.Object whose id is already known by fetching data from - * the server. Either options.success or options.error is called when the - * find completes. - * - * @method get - * @param {String} objectId The id of the object to be fetched. - * @param {Object} options A Backbone-style options object. - * Valid options are:
                        - *
                      • success: A Backbone-style success callback - *
                      • error: An Backbone-style error callback. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * - * @return {Parse.Promise} A promise that is resolved with the result when - * the query completes. - */ - - }, { - key: 'get', - value: function (objectId, options) { - this.equalTo('objectId', objectId); - - var firstOptions = {}; - if (options && options.hasOwnProperty('useMasterKey')) { - firstOptions.useMasterKey = options.useMasterKey; - } - if (options && options.hasOwnProperty('sessionToken')) { - firstOptions.sessionToken = options.sessionToken; - } - - return this.first(firstOptions).then(function (response) { - if (response) { - return response; - } - - var errorObject = new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'Object not found.'); - return _ParsePromise2.default.error(errorObject); - })._thenRunCallbacks(options, null); - } - - /** - * Retrieves a list of ParseObjects that satisfy this query. - * Either options.success or options.error is called when the find - * completes. - * - * @method find - * @param {Object} options A Backbone-style options object. Valid options - * are:
                        - *
                      • success: Function to call when the find completes successfully. - *
                      • error: Function to call when the find fails. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * - * @return {Parse.Promise} A promise that is resolved with the results when - * the query completes. - */ - - }, { - key: 'find', - value: function (options) { - var _this2 = this; - - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var select = this._select; - - return controller.find(this.className, this.toJSON(), findOptions).then(function (response) { - return response.results.map(function (data) { - // In cases of relations, the server may send back a className - // on the top level of the payload - var override = response.className || _this2.className; - if (!data.className) { - data.className = override; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(data, select); - } - - return _ParseObject2.default.fromJSON(data, !select); - }); - })._thenRunCallbacks(options); - } - - /** - * Counts the number of objects that match this query. - * Either options.success or options.error is called when the count - * completes. - * - * @method count - * @param {Object} options A Backbone-style options object. Valid options - * are:
                        - *
                      • success: Function to call when the count completes successfully. - *
                      • error: Function to call when the find fails. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * - * @return {Parse.Promise} A promise that is resolved with the count when - * the query completes. - */ - - }, { - key: 'count', - value: function (options) { - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var params = this.toJSON(); - params.limit = 0; - params.count = 1; - - return controller.find(this.className, params, findOptions).then(function (result) { - return result.count; - })._thenRunCallbacks(options); - } - - /** - * Retrieves at most one Parse.Object that satisfies this query. - * - * Either options.success or options.error is called when it completes. - * success is passed the object if there is one. otherwise, undefined. - * - * @method first - * @param {Object} options A Backbone-style options object. Valid options - * are:
                        - *
                      • success: Function to call when the find completes successfully. - *
                      • error: Function to call when the find fails. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * - * @return {Parse.Promise} A promise that is resolved with the object when - * the query completes. - */ - - }, { - key: 'first', - value: function (options) { - var _this3 = this; - - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var params = this.toJSON(); - params.limit = 1; - - var select = this._select; - - return controller.find(this.className, params, findOptions).then(function (response) { - var objects = response.results; - if (!objects[0]) { - return undefined; - } - if (!objects[0].className) { - objects[0].className = _this3.className; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(objects[0], select); - } - - return _ParseObject2.default.fromJSON(objects[0], !select); - })._thenRunCallbacks(options); - } - - /** - * Iterates over each result of a query, calling a callback for each one. If - * the callback returns a promise, the iteration will not continue until - * that promise has been fulfilled. If the callback returns a rejected - * promise, then iteration will stop with that error. The items are - * processed in an unspecified order. The query may not have any sort order, - * and may not use limit or skip. - * @method each - * @param {Function} callback Callback that will be called with each result - * of the query. - * @param {Object} options A Backbone-style options object. Valid options - * are:
                        - *
                      • success: Function to call when the iteration completes successfully. - *
                      • error: Function to call when the iteration fails. - *
                      • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                      • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                      - * @return {Parse.Promise} A promise that will be fulfilled once the - * iteration has completed. - */ - - }, { - key: 'each', - value: function (callback, options) { - options = options || {}; - - if (this._order || this._skip || this._limit >= 0) { - return _ParsePromise2.default.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); - } - - new _ParsePromise2.default(); - - - var query = new ParseQuery(this.className); - // We can override the batch size from the options. - // This is undocumented, but useful for testing. - query._limit = options.batchSize || 100; - query._include = this._include.map(function (i) { - return i; - }); - if (this._select) { - query._select = this._select.map(function (s) { - return s; - }); - } - - query._where = {}; - for (var attr in this._where) { - var val = this._where[attr]; - if (Array.isArray(val)) { - query._where[attr] = val.map(function (v) { - return v; - }); - } else if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object') { - var conditionMap = {}; - query._where[attr] = conditionMap; - for (var cond in val) { - conditionMap[cond] = val[cond]; - } - } else { - query._where[attr] = val; - } - } - - query.ascending('objectId'); - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var finished = false; - return _ParsePromise2.default._continueWhile(function () { - return !finished; - }, function () { - return query.find(findOptions).then(function (results) { - var callbacksDone = _ParsePromise2.default.as(); - results.forEach(function (result) { - callbacksDone = callbacksDone.then(function () { - return callback(result); - }); - }); - - return callbacksDone.then(function () { - if (results.length >= query._limit) { - query.greaterThan('objectId', results[results.length - 1].id); - } else { - finished = true; - } - }); - }); - })._thenRunCallbacks(options); - } - - /** Query Conditions **/ - - /** - * Adds a constraint to the query that requires a particular key's value to - * be equal to the provided value. - * @method equalTo - * @param {String} key The key to check. - * @param value The value that the Parse.Object must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'equalTo', - value: function (key, value) { - if (typeof value === 'undefined') { - return this.doesNotExist(key); - } - - this._where[key] = (0, _encode2.default)(value, false, true); - return this; - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be not equal to the provided value. - * @method notEqualTo - * @param {String} key The key to check. - * @param value The value that must not be equalled. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'notEqualTo', - value: function (key, value) { - return this._addCondition(key, '$ne', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than the provided value. - * @method lessThan - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'lessThan', - value: function (key, value) { - return this._addCondition(key, '$lt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than the provided value. - * @method greaterThan - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'greaterThan', - value: function (key, value) { - return this._addCondition(key, '$gt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than or equal to the provided value. - * @method lessThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'lessThanOrEqualTo', - value: function (key, value) { - return this._addCondition(key, '$lte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than or equal to the provided value. - * @method greaterThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'greaterThanOrEqualTo', - value: function (key, value) { - return this._addCondition(key, '$gte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be contained in the provided list of values. - * @method containedIn - * @param {String} key The key to check. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containedIn', - value: function (key, value) { - return this._addCondition(key, '$in', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * not be contained in the provided list of values. - * @method notContainedIn - * @param {String} key The key to check. - * @param {Array} values The values that will not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'notContainedIn', - value: function (key, value) { - return this._addCondition(key, '$nin', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values. - * @method containsAll - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containsAll', - value: function (key, values) { - return this._addCondition(key, '$all', values); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values starting with given strings. - * @method containsAllStartingWith - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The string values that will match as starting string. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containsAllStartingWith', - value: function (key, values) { - var _this = this; - if (!Array.isArray(values)) { - values = [values]; - } - - values = values.map(function (value) { - return { "$regex": _this._regexStartWith(value) }; - }); - - return this.containsAll(key, values); - } - - /** - * Adds a constraint for finding objects that contain the given key. - * @method exists - * @param {String} key The key that should exist. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'exists', - value: function (key) { - return this._addCondition(key, '$exists', true); - } - - /** - * Adds a constraint for finding objects that do not contain a given key. - * @method doesNotExist - * @param {String} key The key that should not exist - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotExist', - value: function (key) { - return this._addCondition(key, '$exists', false); - } - - /** - * Adds a regular expression constraint for finding string values that match - * the provided regular expression. - * This may be slow for large datasets. - * @method matches - * @param {String} key The key that the string to match is stored in. - * @param {RegExp} regex The regular expression pattern to match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matches', - value: function (key, regex, modifiers) { - this._addCondition(key, '$regex', regex); - if (!modifiers) { - modifiers = ''; - } - if (regex.ignoreCase) { - modifiers += 'i'; - } - if (regex.multiline) { - modifiers += 'm'; - } - if (modifiers.length) { - this._addCondition(key, '$options', modifiers); - } - return this; - } - - /** - * Adds a constraint that requires that a key's value matches a Parse.Query - * constraint. - * @method matchesQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matchesQuery', - value: function (key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$inQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value not matches a - * Parse.Query constraint. - * @method doesNotMatchQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotMatchQuery', - value: function (key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$notInQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value matches a value in - * an object returned by a different Parse.Query. - * @method matchesKeyInQuery - * @param {String} key The key that contains the value that is being - * matched. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matchesKeyInQuery', - value: function (key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$select', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint that requires that a key's value not match a value in - * an object returned by a different Parse.Query. - * @method doesNotMatchKeyInQuery - * @param {String} key The key that contains the value that is being - * excluded. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotMatchKeyInQuery', - value: function (key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$dontSelect', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint for finding string values that contain a provided - * string. This may be slow for large datasets. - * @method contains - * @param {String} key The key that the string to match is stored in. - * @param {String} substring The substring that the value must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'contains', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value)); - } - - /** - * Adds a constraint for finding string values that start with a provided - * string. This query will use the backend index, so it will be fast even - * for large datasets. - * @method startsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} prefix The substring that the value must start with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'startsWith', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', this._regexStartWith(value)); - } - - /** - * Adds a constraint for finding string values that end with a provided - * string. This will be slow for large datasets. - * @method endsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} suffix The substring that the value must end with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'endsWith', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value) + '$'); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given. - * @method near - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'near', - value: function (key, point) { - if (!(point instanceof _ParseGeoPoint2.default)) { - // Try to cast it as a GeoPoint - point = new _ParseGeoPoint2.default(point); - } - return this._addCondition(key, '$nearSphere', point); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * @method withinRadians - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in radians) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinRadians', - value: function (key, point, distance) { - this.near(key, point); - return this._addCondition(key, '$maxDistance', distance); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 3958.8 miles. - * @method withinMiles - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in miles) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinMiles', - value: function (key, point, distance) { - return this.withinRadians(key, point, distance / 3958.8); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 6371.0 kilometers. - * @method withinKilometers - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in kilometers) of results - * to return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinKilometers', - value: function (key, point, distance) { - return this.withinRadians(key, point, distance / 6371.0); - } - - /** - * Adds a constraint to the query that requires a particular key's - * coordinates be contained within a given rectangular geographic bounding - * box. - * @method withinGeoBox - * @param {String} key The key to be constrained. - * @param {Parse.GeoPoint} southwest - * The lower-left inclusive corner of the box. - * @param {Parse.GeoPoint} northeast - * The upper-right inclusive corner of the box. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinGeoBox', - value: function (key, southwest, northeast) { - if (!(southwest instanceof _ParseGeoPoint2.default)) { - southwest = new _ParseGeoPoint2.default(southwest); - } - if (!(northeast instanceof _ParseGeoPoint2.default)) { - northeast = new _ParseGeoPoint2.default(northeast); - } - this._addCondition(key, '$within', { '$box': [southwest, northeast] }); - return this; - } - - /** Query Orderings **/ - - /** - * Sorts the results in ascending order by the given key. - * - * @method ascending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'ascending', - value: function () { - this._order = []; - - for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) { - keys[_key] = arguments[_key]; - } - - return this.addAscending.apply(this, keys); - } - - /** - * Sorts the results in ascending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addAscending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'addAscending', - value: function () { - var _this4 = this; - - if (!this._order) { - this._order = []; - } - - for (var _len2 = arguments.length, keys = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - keys[_key2] = arguments[_key2]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - key = key.join(); - } - _this4._order = _this4._order.concat(key.replace(/\s/g, '').split(',')); - }); - - return this; - } - - /** - * Sorts the results in descending order by the given key. - * - * @method descending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'descending', - value: function () { - this._order = []; - - for (var _len3 = arguments.length, keys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - keys[_key3] = arguments[_key3]; - } - - return this.addDescending.apply(this, keys); - } - - /** - * Sorts the results in descending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addDescending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'addDescending', - value: function () { - var _this5 = this; - - if (!this._order) { - this._order = []; - } - - for (var _len4 = arguments.length, keys = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - keys[_key4] = arguments[_key4]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - key = key.join(); - } - _this5._order = _this5._order.concat(key.replace(/\s/g, '').split(',').map(function (k) { - return '-' + k; - })); - }); - - return this; - } - - /** Query Options **/ - - /** - * Sets the number of results to skip before returning any results. - * This is useful for pagination. - * Default is to skip zero results. - * @method skip - * @param {Number} n the number of results to skip. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'skip', - value: function (n) { - if (typeof n !== 'number' || n < 0) { - throw new Error('You can only skip by a positive number'); - } - this._skip = n; - return this; - } - - /** - * Sets the limit of the number of results to return. The default limit is - * 100, with a maximum of 1000 results being returned at a time. - * @method limit - * @param {Number} n the number of results to limit to. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'limit', - value: function (n) { - if (typeof n !== 'number') { - throw new Error('You can only set the limit to a numeric value'); - } - this._limit = n; - return this; - } - - /** - * Includes nested Parse.Objects for the provided key. You can use dot - * notation to specify which fields in the included object are also fetched. - * @method include - * @param {String} key The name of the key to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'include', - value: function () { - var _this6 = this; - - for (var _len5 = arguments.length, keys = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - keys[_key5] = arguments[_key5]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - _this6._include = _this6._include.concat(key); - } else { - _this6._include.push(key); - } - }); - return this; - } - - /** - * Restricts the fields of the returned Parse.Objects to include only the - * provided keys. If this is called multiple times, then all of the keys - * specified in each of the calls will be included. - * @method select - * @param {Array} keys The names of the keys to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'select', - value: function () { - var _this7 = this; - - if (!this._select) { - this._select = []; - } - - for (var _len6 = arguments.length, keys = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - keys[_key6] = arguments[_key6]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - _this7._select = _this7._select.concat(key); - } else { - _this7._select.push(key); - } - }); - return this; - } - - /** - * Subscribe this query to get liveQuery updates - * @method subscribe - * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter - * which can be used to get liveQuery updates. - */ - - }, { - key: 'subscribe', - value: function () { - var controller = _CoreManager2.default.getLiveQueryController(); - return controller.subscribe(this); - } - - /** - * Constructs a Parse.Query that is the OR of the passed in queries. For - * example: - *
                      var compoundQuery = Parse.Query.or(query1, query2, query3);
                      - * - * will create a compoundQuery that is an or of the query1, query2, and - * query3. - * @method or - * @param {...Parse.Query} var_args The list of queries to OR. - * @static - * @return {Parse.Query} The query that is the OR of the passed in queries. - */ - - }], [{ - key: 'or', - value: function () { - var className = null; - - for (var _len7 = arguments.length, queries = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - queries[_key7] = arguments[_key7]; - } - - queries.forEach(function (q) { - if (!className) { - className = q.className; - } - - if (className !== q.className) { - throw new Error('All queries must be for the same class.'); - } - }); - - var query = new ParseQuery(className); - query._orQuery(queries); - return query; - } - }]); - return ParseQuery; -}(); - -exports.default = ParseQuery; - -var DefaultController = { - find: function (className, params, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - return RESTController.request('GET', 'classes/' + className, params, options); - } -}; - -_CoreManager2.default.setQueryController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseRelation.js b/lib/browser/ParseRelation.js deleted file mode 100644 index fe9ea8769..000000000 --- a/lib/browser/ParseRelation.js +++ /dev/null @@ -1,182 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParseOp = require('./ParseOp'); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseQuery = require('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new Relation for the given parent object and key. This - * constructor should rarely be used directly, but rather created by - * Parse.Object.relation. - * @class Parse.Relation - * @constructor - * @param {Parse.Object} parent The parent of this relation. - * @param {String} key The key for this relation on the parent. - * - *

                      - * A class that is used to access all of the children of a many-to-many - * relationship. Each instance of Parse.Relation is associated with a - * particular parent object and key. - *

                      - */ -var ParseRelation = function () { - function ParseRelation(parent, key) { - (0, _classCallCheck3.default)(this, ParseRelation); - - this.parent = parent; - this.key = key; - this.targetClassName = null; - } - - /** - * Makes sure that this relation has the right parent and key. - */ - - (0, _createClass3.default)(ParseRelation, [{ - key: '_ensureParentAndKey', - value: function (parent, key) { - this.key = this.key || key; - if (this.key !== key) { - throw new Error('Internal Error. Relation retrieved from two different keys.'); - } - if (this.parent) { - if (this.parent.className !== parent.className) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - if (this.parent.id) { - if (this.parent.id !== parent.id) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - } else if (parent.id) { - this.parent = parent; - } - } else { - this.parent = parent; - } - } - - /** - * Adds a Parse.Object or an array of Parse.Objects to the relation. - * @method add - * @param {} objects The item or items to add. - */ - - }, { - key: 'add', - value: function (objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new _ParseOp.RelationOp(objects, []); - var parent = this.parent; - if (!parent) { - throw new Error('Cannot add to a Relation without a parent'); - } - parent.set(this.key, change); - this.targetClassName = change._targetClassName; - return parent; - } - - /** - * Removes a Parse.Object or an array of Parse.Objects from this relation. - * @method remove - * @param {} objects The item or items to remove. - */ - - }, { - key: 'remove', - value: function (objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new _ParseOp.RelationOp([], objects); - if (!this.parent) { - throw new Error('Cannot remove from a Relation without a parent'); - } - this.parent.set(this.key, change); - this.targetClassName = change._targetClassName; - } - - /** - * Returns a JSON version of the object suitable for saving to disk. - * @method toJSON - * @return {Object} - */ - - }, { - key: 'toJSON', - value: function () { - return { - __type: 'Relation', - className: this.targetClassName - }; - } - - /** - * Returns a Parse.Query that is limited to objects in this - * relation. - * @method query - * @return {Parse.Query} - */ - - }, { - key: 'query', - value: function () { - var query; - var parent = this.parent; - if (!parent) { - throw new Error('Cannot construct a query for a Relation without a parent'); - } - if (!this.targetClassName) { - query = new _ParseQuery2.default(parent.className); - query._extraOptions.redirectClassNameForKey = this.key; - } else { - query = new _ParseQuery2.default(this.targetClassName); - } - query._addCondition('$relatedTo', 'object', { - __type: 'Pointer', - className: parent.className, - objectId: parent.id - }); - query._addCondition('$relatedTo', 'key', this.key); - - return query; - } - }]); - return ParseRelation; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseRelation; \ No newline at end of file diff --git a/lib/browser/ParseRole.js b/lib/browser/ParseRole.js deleted file mode 100644 index 567af7a54..000000000 --- a/lib/browser/ParseRole.js +++ /dev/null @@ -1,196 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _get2 = require('babel-runtime/helpers/get'); - -var _get3 = _interopRequireDefault(_get2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Represents a Role on the Parse server. Roles represent groupings of - * Users for the purposes of granting permissions (e.g. specifying an ACL - * for an Object). Roles are specified by their sets of child users and - * child roles, all of which are granted any permissions that the parent - * role has. - * - *

                      Roles must have a name (which cannot be changed after creation of the - * role), and must specify an ACL.

                      - * @class Parse.Role - * @constructor - * @param {String} name The name of the Role to create. - * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. - * A Parse.Role is a local representation of a role persisted to the Parse - * cloud. - */ -var ParseRole = function (_ParseObject) { - (0, _inherits3.default)(ParseRole, _ParseObject); - - function ParseRole(name, acl) { - (0, _classCallCheck3.default)(this, ParseRole); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseRole.__proto__ || (0, _getPrototypeOf2.default)(ParseRole)).call(this, '_Role')); - - if (typeof name === 'string' && acl instanceof _ParseACL2.default) { - _this.setName(name); - _this.setACL(acl); - } - return _this; - } - - /** - * Gets the name of the role. You can alternatively call role.get("name") - * - * @method getName - * @return {String} the name of the role. - */ - - (0, _createClass3.default)(ParseRole, [{ - key: 'getName', - value: function () { - var name = this.get('name'); - if (name == null || typeof name === 'string') { - return name; - } - return ''; - } - - /** - * Sets the name for a role. This value must be set before the role has - * been saved to the server, and cannot be set once the role has been - * saved. - * - *

                      - * A role's name can only contain alphanumeric characters, _, -, and - * spaces. - *

                      - * - *

                      This is equivalent to calling role.set("name", name)

                      - * - * @method setName - * @param {String} name The name of the role. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - - }, { - key: 'setName', - value: function (name, options) { - return this.set('name', name, options); - } - - /** - * Gets the Parse.Relation for the Parse.Users that are direct - * children of this role. These users are granted any privileges that this - * role has been granted (e.g. read or write access through ACLs). You can - * add or remove users from the role through this relation. - * - *

                      This is equivalent to calling role.relation("users")

                      - * - * @method getUsers - * @return {Parse.Relation} the relation for the users belonging to this - * role. - */ - - }, { - key: 'getUsers', - value: function () { - return this.relation('users'); - } - - /** - * Gets the Parse.Relation for the Parse.Roles that are direct - * children of this role. These roles' users are granted any privileges that - * this role has been granted (e.g. read or write access through ACLs). You - * can add or remove child roles from this role through this relation. - * - *

                      This is equivalent to calling role.relation("roles")

                      - * - * @method getRoles - * @return {Parse.Relation} the relation for the roles belonging to this - * role. - */ - - }, { - key: 'getRoles', - value: function () { - return this.relation('roles'); - } - }, { - key: 'validate', - value: function (attrs, options) { - var isInvalid = (0, _get3.default)(ParseRole.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseRole.prototype), 'validate', this).call(this, attrs, options); - if (isInvalid) { - return isInvalid; - } - - if ('name' in attrs && attrs.name !== this.getName()) { - var newName = attrs.name; - if (this.id && this.id !== attrs.objectId) { - // Check to see if the objectId being set matches this.id - // This happens during a fetch -- the id is set before calling fetch - // Let the name be set in this case - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); - } - if (typeof newName !== 'string') { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name must be a String.'); - } - if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); - } - } - return false; - } - }]); - return ParseRole; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseRole; - -_ParseObject3.default.registerSubclass('_Role', ParseRole); \ No newline at end of file diff --git a/lib/browser/ParseSession.js b/lib/browser/ParseSession.js deleted file mode 100644 index 7fb75c80d..000000000 --- a/lib/browser/ParseSession.js +++ /dev/null @@ -1,180 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _isRevocableSession = require('./isRevocableSession'); - -var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseUser = require('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * @class Parse.Session - * @constructor - * - *

                      A Parse.Session object is a local representation of a revocable session. - * This class is a subclass of a Parse.Object, and retains the same - * functionality of a Parse.Object.

                      - */ -var ParseSession = function (_ParseObject) { - (0, _inherits3.default)(ParseSession, _ParseObject); - - function ParseSession(attributes) { - (0, _classCallCheck3.default)(this, ParseSession); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseSession.__proto__ || (0, _getPrototypeOf2.default)(ParseSession)).call(this, '_Session')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - return _this; - } - - /** - * Returns the session token string. - * @method getSessionToken - * @return {String} - */ - - (0, _createClass3.default)(ParseSession, [{ - key: 'getSessionToken', - value: function () { - var token = this.get('sessionToken'); - if (typeof token === 'string') { - return token; - } - return ''; - } - }], [{ - key: 'readOnlyAttributes', - value: function () { - return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; - } - - /** - * Retrieves the Session object for the currently logged in session. - * @method current - * @static - * @return {Parse.Promise} A promise that is resolved with the Parse.Session - * object after it has been fetched. If there is no current user, the - * promise will be rejected. - */ - - }, { - key: 'current', - value: function (options) { - options = options || {}; - var controller = _CoreManager2.default.getSessionController(); - - var sessionOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - sessionOptions.useMasterKey = options.useMasterKey; - } - return _ParseUser2.default.currentAsync().then(function (user) { - if (!user) { - return _ParsePromise2.default.error('There is no current user.'); - } - user.getSessionToken(); - - sessionOptions.sessionToken = user.getSessionToken(); - return controller.getSession(sessionOptions); - }); - } - - /** - * Determines whether the current session token is revocable. - * This method is useful for migrating Express.js or Node.js web apps to - * use revocable sessions. If you are migrating an app that uses the Parse - * SDK in the browser only, please use Parse.User.enableRevocableSession() - * instead, so that sessions can be automatically upgraded. - * @method isCurrentSessionRevocable - * @static - * @return {Boolean} - */ - - }, { - key: 'isCurrentSessionRevocable', - value: function () { - var currentUser = _ParseUser2.default.current(); - if (currentUser) { - return (0, _isRevocableSession2.default)(currentUser.getSessionToken() || ''); - } - return false; - } - }]); - return ParseSession; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseSession; - -_ParseObject3.default.registerSubclass('_Session', ParseSession); - -var DefaultController = { - getSession: function (options) { - var RESTController = _CoreManager2.default.getRESTController(); - var session = new ParseSession(); - - return RESTController.request('GET', 'sessions/me', {}, options).then(function (sessionData) { - session._finishFetch(sessionData); - session._setExisted(true); - return session; - }); - } -}; - -_CoreManager2.default.setSessionController(DefaultController); \ No newline at end of file diff --git a/lib/browser/ParseUser.js b/lib/browser/ParseUser.js deleted file mode 100644 index f18f42820..000000000 --- a/lib/browser/ParseUser.js +++ /dev/null @@ -1,1150 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _defineProperty = require('babel-runtime/core-js/object/define-property'); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _get2 = require('babel-runtime/helpers/get'); - -var _get3 = _interopRequireDefault(_get2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _isRevocableSession = require('./isRevocableSession'); - -var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseSession = require('./ParseSession'); - -var _ParseSession2 = _interopRequireDefault(_ParseSession); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var CURRENT_USER_KEY = 'currentUser'; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var canUseCurrentUser = !_CoreManager2.default.get('IS_NODE'); -var currentUserCacheMatchesDisk = false; -var currentUserCache = null; - -var authProviders = {}; - -/** - * @class Parse.User - * @constructor - * - *

                      A Parse.User object is a local representation of a user persisted to the - * Parse cloud. This class is a subclass of a Parse.Object, and retains the - * same functionality of a Parse.Object, but also extends it with various - * user specific methods, like authentication, signing up, and validation of - * uniqueness.

                      - */ - -var ParseUser = function (_ParseObject) { - (0, _inherits3.default)(ParseUser, _ParseObject); - - function ParseUser(attributes) { - (0, _classCallCheck3.default)(this, ParseUser); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseUser.__proto__ || (0, _getPrototypeOf2.default)(ParseUser)).call(this, '_User')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Parse User'); - } - } - return _this; - } - - /** - * Request a revocable session token to replace the older style of token. - * @method _upgradeToRevocableSession - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is resolved when the replacement - * token has been fetched. - */ - - (0, _createClass3.default)(ParseUser, [{ - key: '_upgradeToRevocableSession', - value: function (options) { - options = options || {}; - - var upgradeOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - upgradeOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); - } - - /** - * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can - * call linkWith on the user (even if it doesn't exist yet on the server). - * @method _linkWith - */ - - }, { - key: '_linkWith', - value: function (provider, options) { - var _this2 = this; - - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[provider]; - } else { - authType = provider.getAuthType(); - } - if (options && options.hasOwnProperty('authData')) { - var authData = this.get('authData') || {}; - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - throw new Error('Invalid type: authData field should be an object'); - } - authData[authType] = options.authData; - - var controller = _CoreManager2.default.getUserController(); - return controller.linkWith(this, authData)._thenRunCallbacks(options, this); - } else { - var promise = new _ParsePromise2.default(); - provider.authenticate({ - success: function (provider, result) { - var opts = {}; - opts.authData = result; - if (options.success) { - opts.success = options.success; - } - if (options.error) { - opts.error = options.error; - } - _this2._linkWith(provider, opts).then(function () { - promise.resolve(_this2); - }, function (error) { - promise.reject(error); - }); - }, - error: function (provider, _error) { - if (typeof options.error === 'function') { - options.error(_this2, _error); - } - promise.reject(_error); - } - }); - return promise; - } - } - - /** - * Synchronizes auth data for a provider (e.g. puts the access token in the - * right place to be used by the Facebook SDK). - * @method _synchronizeAuthData - */ - - }, { - key: '_synchronizeAuthData', - value: function (provider) { - if (!this.isCurrent() || !provider) { - return; - } - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[authType]; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData'); - if (!provider || !authData || (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - var success = provider.restoreAuthentication(authData[authType]); - if (!success) { - this._unlinkFrom(provider); - } - } - - /** - * Synchronizes authData for all providers. - * @method _synchronizeAllAuthData - */ - - }, { - key: '_synchronizeAllAuthData', - value: function () { - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - this._synchronizeAuthData(key); - } - } - - /** - * Removes null values from authData (which exist temporarily for - * unlinking) - * @method _cleanupAuthData - */ - - }, { - key: '_cleanupAuthData', - value: function () { - if (!this.isCurrent()) { - return; - } - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - if (!authData[key]) { - delete authData[key]; - } - } - } - - /** - * Unlinks a user from a service. - * @method _unlinkFrom - */ - - }, { - key: '_unlinkFrom', - value: function (provider, options) { - var _this3 = this; - - if (typeof provider === 'string') { - provider = authProviders[provider]; - } else { - provider.getAuthType(); - } - return this._linkWith(provider, { authData: null }).then(function () { - _this3._synchronizeAuthData(provider); - return _ParsePromise2.default.as(_this3); - })._thenRunCallbacks(options); - } - - /** - * Checks whether a user is linked to a service. - * @method _isLinked - */ - - }, { - key: '_isLinked', - value: function (provider) { - var authType; - if (typeof provider === 'string') { - authType = provider; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData') || {}; - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return false; - } - return !!authData[authType]; - } - - /** - * Deauthenticates all providers. - * @method _logOutWithAll - */ - - }, { - key: '_logOutWithAll', - value: function () { - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - this._logOutWith(key); - } - } - - /** - * Deauthenticates a single provider (e.g. removing access tokens from the - * Facebook SDK). - * @method _logOutWith - */ - - }, { - key: '_logOutWith', - value: function (provider) { - if (!this.isCurrent()) { - return; - } - if (typeof provider === 'string') { - provider = authProviders[provider]; - } - if (provider && provider.deauthenticate) { - provider.deauthenticate(); - } - } - - /** - * Class instance method used to maintain specific keys when a fetch occurs. - * Used to ensure that the session token is not lost. - */ - - }, { - key: '_preserveFieldsOnFetch', - value: function () { - return { - sessionToken: this.get('sessionToken') - }; - } - - /** - * Returns true if current would return this user. - * @method isCurrent - * @return {Boolean} - */ - - }, { - key: 'isCurrent', - value: function () { - var current = ParseUser.current(); - return !!current && current.id === this.id; - } - - /** - * Returns get("username"). - * @method getUsername - * @return {String} - */ - - }, { - key: 'getUsername', - value: function () { - var username = this.get('username'); - if (username == null || typeof username === 'string') { - return username; - } - return ''; - } - - /** - * Calls set("username", username, options) and returns the result. - * @method setUsername - * @param {String} username - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setUsername', - value: function (username) { - // Strip anonymity, even we do not support anonymous user in js SDK, we may - // encounter anonymous user created by android/iOS in cloud code. - var authData = this.get('authData'); - if (authData && (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) === 'object' && authData.hasOwnProperty('anonymous')) { - // We need to set anonymous to null instead of deleting it in order to remove it from Parse. - authData.anonymous = null; - } - this.set('username', username); - } - - /** - * Calls set("password", password, options) and returns the result. - * @method setPassword - * @param {String} password - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setPassword', - value: function (password) { - this.set('password', password); - } - - /** - * Returns get("email"). - * @method getEmail - * @return {String} - */ - - }, { - key: 'getEmail', - value: function () { - var email = this.get('email'); - if (email == null || typeof email === 'string') { - return email; - } - return ''; - } - - /** - * Calls set("email", email, options) and returns the result. - * @method setEmail - * @param {String} email - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setEmail', - value: function (email) { - this.set('email', email); - } - - /** - * Returns the session token for this user, if the user has been logged in, - * or if it is the result of a query with the master key. Otherwise, returns - * undefined. - * @method getSessionToken - * @return {String} the session token, or undefined - */ - - }, { - key: 'getSessionToken', - value: function () { - var token = this.get('sessionToken'); - if (token == null || typeof token === 'string') { - return token; - } - return ''; - } - - /** - * Checks whether this user is the current user and has been authenticated. - * @method authenticated - * @return (Boolean) whether this user is the current user and is logged in. - */ - - }, { - key: 'authenticated', - value: function () { - var current = ParseUser.current(); - return !!this.get('sessionToken') && !!current && current.id === this.id; - } - - /** - * Signs up a new user. You should call this instead of save for - * new Parse.Users. This will create a new Parse.User on the server, and - * also persist the session on disk so that you can access the user using - * current. - * - *

                      A username and password must be set before calling signUp.

                      - * - *

                      Calls options.success or options.error on completion.

                      - * - * @method signUp - * @param {Object} attrs Extra fields to set on the new user, or null. - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled when the signup - * finishes. - */ - - }, { - key: 'signUp', - value: function (attrs, options) { - options = options || {}; - - var signupOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - signupOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - signupOptions.installationId = options.installationId; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); - } - - /** - * Logs in a Parse.User. On success, this saves the session to disk, - * so you can retrieve the currently logged in user using - * current. - * - *

                      A username and password must be set before calling logIn.

                      - * - *

                      Calls options.success or options.error on completion.

                      - * - * @method logIn - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login is complete. - */ - - }, { - key: 'logIn', - value: function (options) { - options = options || {}; - - var loginOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - loginOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - loginOptions.installationId = options.installationId; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); - } - - /** - * Wrap the default save behavior with functionality to save to local - * storage if this is current user. - */ - - }, { - key: 'save', - value: function () { - var _this4 = this; - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'save', this).apply(this, args).then(function () { - if (_this4.isCurrent()) { - return _CoreManager2.default.getUserController().updateUserOnDisk(_this4); - } - return _this4; - }); - } - - /** - * Wrap the default destroy behavior with functionality that logs out - * the current user when it is destroyed - */ - - }, { - key: 'destroy', - value: function () { - var _this5 = this; - - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'destroy', this).apply(this, args).then(function () { - if (_this5.isCurrent()) { - return _CoreManager2.default.getUserController().removeUserFromDisk(); - } - return _this5; - }); - } - - /** - * Wrap the default fetch behavior with functionality to save to local - * storage if this is current user. - */ - - }, { - key: 'fetch', - value: function () { - var _this6 = this; - - for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'fetch', this).apply(this, args).then(function () { - if (_this6.isCurrent()) { - return _CoreManager2.default.getUserController().updateUserOnDisk(_this6); - } - return _this6; - }); - } - }], [{ - key: 'readOnlyAttributes', - value: function () { - return ['sessionToken']; - } - - /** - * Adds functionality to the existing Parse.User class - * @method extend - * @param {Object} protoProps A set of properties to add to the prototype - * @param {Object} classProps A set of static properties to add to the class - * @static - * @return {Class} The newly extended Parse.User class - */ - - }, { - key: 'extend', - value: function (protoProps, classProps) { - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseUser.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseUser, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - return ParseUser; - } - - /** - * Retrieves the currently logged in ParseUser with a valid session, - * either from memory or localStorage, if necessary. - * @method current - * @static - * @return {Parse.Object} The currently logged in Parse.User. - */ - - }, { - key: 'current', - value: function () { - if (!canUseCurrentUser) { - return null; - } - var controller = _CoreManager2.default.getUserController(); - return controller.currentUser(); - } - - /** - * Retrieves the currently logged in ParseUser from asynchronous Storage. - * @method currentAsync - * @static - * @return {Parse.Promise} A Promise that is resolved with the currently - * logged in Parse User - */ - - }, { - key: 'currentAsync', - value: function () { - if (!canUseCurrentUser) { - return _ParsePromise2.default.as(null); - } - var controller = _CoreManager2.default.getUserController(); - return controller.currentUserAsync(); - } - - /** - * Signs up a new user with a username (or email) and password. - * This will create a new Parse.User on the server, and also persist the - * session in localStorage so that you can access the user using - * {@link #current}. - * - *

                      Calls options.success or options.error on completion.

                      - * - * @method signUp - * @param {String} username The username (or email) to sign up with. - * @param {String} password The password to sign up with. - * @param {Object} attrs Extra fields to set on the new user. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the signup completes. - */ - - }, { - key: 'signUp', - value: function (username, password, attrs, options) { - attrs = attrs || {}; - attrs.username = username; - attrs.password = password; - var user = new ParseUser(attrs); - return user.signUp({}, options); - } - - /** - * Logs in a user with a username (or email) and password. On success, this - * saves the session to disk, so you can retrieve the currently logged in - * user using current. - * - *

                      Calls options.success or options.error on completion.

                      - * - * @method logIn - * @param {String} username The username (or email) to log in with. - * @param {String} password The password to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - - }, { - key: 'logIn', - value: function (username, password, options) { - if (typeof username !== 'string') { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Username must be a string.')); - } else if (typeof password !== 'string') { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Password must be a string.')); - } - var user = new ParseUser(); - user._finishFetch({ username: username, password: password }); - return user.logIn(options); - } - - /** - * Logs in a user with a session token. On success, this saves the session - * to disk, so you can retrieve the currently logged in user using - * current. - * - *

                      Calls options.success or options.error on completion.

                      - * - * @method become - * @param {String} sessionToken The sessionToken to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - - }, { - key: 'become', - value: function (sessionToken, options) { - if (!canUseCurrentUser) { - throw new Error('It is not memory-safe to become a user in a server environment'); - } - options = options || {}; - - var becomeOptions = { - sessionToken: sessionToken - }; - if (options.hasOwnProperty('useMasterKey')) { - becomeOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.become(becomeOptions)._thenRunCallbacks(options); - } - }, { - key: 'logInWith', - value: function (provider, options) { - return ParseUser._logInWith(provider, options); - } - - /** - * Logs out the currently logged in user session. This will remove the - * session from disk, log out of linked services, and future calls to - * current will return null. - * @method logOut - * @static - * @return {Parse.Promise} A promise that is resolved when the session is - * destroyed on the server. - */ - - }, { - key: 'logOut', - value: function () { - if (!canUseCurrentUser) { - throw new Error('There is no current user user on a node.js server environment.'); - } - - var controller = _CoreManager2.default.getUserController(); - return controller.logOut(); - } - - /** - * Requests a password reset email to be sent to the specified email address - * associated with the user account. This email allows the user to securely - * reset their password on the Parse site. - * - *

                      Calls options.success or options.error on completion.

                      - * - * @method requestPasswordReset - * @param {String} email The email address associated with the user that - * forgot their password. - * @param {Object} options A Backbone-style options object. - * @static - */ - - }, { - key: 'requestPasswordReset', - value: function (email, options) { - options = options || {}; - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); - } - - /** - * Allow someone to define a custom User class without className - * being rewritten to _User. The default behavior is to rewrite - * User to _User for legacy reasons. This allows developers to - * override that behavior. - * - * @method allowCustomUserClass - * @param {Boolean} isAllowed Whether or not to allow custom User class - * @static - */ - - }, { - key: 'allowCustomUserClass', - value: function (isAllowed) { - _CoreManager2.default.set('PERFORM_USER_REWRITE', !isAllowed); - } - - /** - * Allows a legacy application to start using revocable sessions. If the - * current session token is not revocable, a request will be made for a new, - * revocable session. - * It is not necessary to call this method from cloud code unless you are - * handling user signup or login from the server side. In a cloud code call, - * this function will not attempt to upgrade the current token. - * @method enableRevocableSession - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is resolved when the process has - * completed. If a replacement session token is requested, the promise - * will be resolved after a new token has been fetched. - */ - - }, { - key: 'enableRevocableSession', - value: function (options) { - options = options || {}; - _CoreManager2.default.set('FORCE_REVOCABLE_SESSION', true); - if (canUseCurrentUser) { - var current = ParseUser.current(); - if (current) { - return current._upgradeToRevocableSession(options); - } - } - return _ParsePromise2.default.as()._thenRunCallbacks(options); - } - - /** - * Enables the use of become or the current user in a server - * environment. These features are disabled by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method enableUnsafeCurrentUser - * @static - */ - - }, { - key: 'enableUnsafeCurrentUser', - value: function () { - canUseCurrentUser = true; - } - - /** - * Disables the use of become or the current user in any environment. - * These features are disabled on servers by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method disableUnsafeCurrentUser - * @static - */ - - }, { - key: 'disableUnsafeCurrentUser', - value: function () { - canUseCurrentUser = false; - } - }, { - key: '_registerAuthenticationProvider', - value: function (provider) { - authProviders[provider.getAuthType()] = provider; - // Synchronize the current user with the auth provider. - ParseUser.currentAsync().then(function (current) { - if (current) { - current._synchronizeAuthData(provider.getAuthType()); - } - }); - } - }, { - key: '_logInWith', - value: function (provider, options) { - var user = new ParseUser(); - return user._linkWith(provider, options); - } - }, { - key: '_clearCache', - value: function () { - currentUserCache = null; - currentUserCacheMatchesDisk = false; - } - }, { - key: '_setCurrentUserCache', - value: function (user) { - currentUserCache = user; - } - }]); - return ParseUser; -}(_ParseObject3.default); - -exports.default = ParseUser; - -_ParseObject3.default.registerSubclass('_User', ParseUser); - -var DefaultController = { - updateUserOnDisk: function (user) { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var json = user.toJSON(); - json.className = '_User'; - return _Storage2.default.setItemAsync(path, (0, _stringify2.default)(json)).then(function () { - return user; - }); - }, - removeUserFromDisk: function () { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - currentUserCacheMatchesDisk = true; - currentUserCache = null; - return _Storage2.default.removeItemAsync(path); - }, - setCurrentUser: function (user) { - currentUserCache = user; - user._cleanupAuthData(); - user._synchronizeAllAuthData(); - return DefaultController.updateUserOnDisk(user); - }, - currentUser: function () { - if (currentUserCache) { - return currentUserCache; - } - if (currentUserCacheMatchesDisk) { - return null; - } - if (_Storage2.default.async()) { - throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); - } - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var userData = _Storage2.default.getItem(path); - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return null; - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = _ParseObject3.default.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return current; - }, - currentUserAsync: function () { - if (currentUserCache) { - return _ParsePromise2.default.as(currentUserCache); - } - if (currentUserCacheMatchesDisk) { - return _ParsePromise2.default.as(null); - } - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - return _Storage2.default.getItemAsync(path).then(function (userData) { - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return _ParsePromise2.default.as(null); - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = _ParseObject3.default.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return _ParsePromise2.default.as(current); - }); - }, - signUp: function (user, attrs, options) { - var username = attrs && attrs.username || user.get('username'); - var password = attrs && attrs.password || user.get('password'); - - if (!username || !username.length) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); - } - if (!password || !password.length) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); - } - - return user.save(attrs, options).then(function () { - // Clear the password field - user._finishFetch({ password: undefined }); - - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - }, - logIn: function (user, options) { - var RESTController = _CoreManager2.default.getRESTController(); - var stateController = _CoreManager2.default.getObjectStateController(); - var auth = { - username: user.get('username'), - password: user.get('password') - }; - return RESTController.request('GET', 'login', auth, options).then(function (response, status) { - user._migrateId(response.objectId); - user._setExisted(true); - stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); - stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); - response.password = undefined; - user._finishFetch(response); - if (!canUseCurrentUser) { - // We can't set the current user, so just return the one we logged in - return _ParsePromise2.default.as(user); - } - return DefaultController.setCurrentUser(user); - }); - }, - become: function (options) { - var user = new ParseUser(); - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('GET', 'users/me', {}, options).then(function (response, status) { - user._finishFetch(response); - user._setExisted(true); - return DefaultController.setCurrentUser(user); - }); - }, - logOut: function () { - return DefaultController.currentUserAsync().then(function (currentUser) { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var promise = _Storage2.default.removeItemAsync(path); - var RESTController = _CoreManager2.default.getRESTController(); - if (currentUser !== null) { - var currentSession = currentUser.getSessionToken(); - if (currentSession && (0, _isRevocableSession2.default)(currentSession)) { - promise = promise.then(function () { - return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); - }); - } - currentUser._logOutWithAll(); - currentUser._finishFetch({ sessionToken: undefined }); - } - currentUserCacheMatchesDisk = true; - currentUserCache = null; - - return promise; - }); - }, - requestPasswordReset: function (email, options) { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); - }, - upgradeToRevocableSession: function (user, options) { - var token = user.getSessionToken(); - if (!token) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.SESSION_MISSING, 'Cannot upgrade a user with no session token')); - } - - options.sessionToken = token; - - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(function (result) { - var session = new _ParseSession2.default(); - session._finishFetch(result); - user._finishFetch({ sessionToken: session.getSessionToken() }); - if (user.isCurrent()) { - return DefaultController.setCurrentUser(user); - } - return _ParsePromise2.default.as(user); - }); - }, - linkWith: function (user, authData) { - return user.save({ authData: authData }).then(function () { - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - } -}; - -_CoreManager2.default.setUserController(DefaultController); \ No newline at end of file diff --git a/lib/browser/Push.js b/lib/browser/Push.js deleted file mode 100644 index cfb740767..000000000 --- a/lib/browser/Push.js +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.send = send; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParseQuery = require('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains functions to deal with Push in Parse. - * @class Parse.Push - * @static - */ - -/** - * Sends a push notification. - * @method send - * @param {Object} data - The data of the push notification. Valid fields - * are: - *
                        - *
                      1. channels - An Array of channels to push to.
                      2. - *
                      3. push_time - A Date object for when to send the push.
                      4. - *
                      5. expiration_time - A Date object for when to expire - * the push.
                      6. - *
                      7. expiration_interval - The seconds from now to expire the push.
                      8. - *
                      9. where - A Parse.Query over Parse.Installation that is used to match - * a set of installations to push to.
                      10. - *
                      11. data - The data to send as part of the push
                      12. - *
                          - * @param {Object} options An object that has an optional success function, - * that takes no arguments and will be called on a successful push, and - * an error function that takes a Parse.Error and will be called if the push - * failed. - * @return {Parse.Promise} A promise that is fulfilled when the push request - * completes. - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function send(data, options) { - options = options || {}; - - if (data.where && data.where instanceof _ParseQuery2.default) { - data.where = data.where.toJSON().where; - } - - if (data.push_time && (0, _typeof3.default)(data.push_time) === 'object') { - data.push_time = data.push_time.toJSON(); - } - - if (data.expiration_time && (0, _typeof3.default)(data.expiration_time) === 'object') { - data.expiration_time = data.expiration_time.toJSON(); - } - - if (data.expiration_time && data.expiration_interval) { - throw new Error('expiration_time and expiration_interval cannot both be set.'); - } - - return _CoreManager2.default.getPushController().send(data, { - useMasterKey: options.useMasterKey - })._thenRunCallbacks(options); -} - -var DefaultController = { - send: function (data, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); - - return request._thenRunCallbacks(options); - } -}; - -_CoreManager2.default.setPushController(DefaultController); \ No newline at end of file diff --git a/lib/browser/RESTController.js b/lib/browser/RESTController.js deleted file mode 100644 index f8ea70e2f..000000000 --- a/lib/browser/RESTController.js +++ /dev/null @@ -1,248 +0,0 @@ -'use strict'; - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var XHR = null; -if (typeof XMLHttpRequest !== 'undefined') { - XHR = XMLHttpRequest; -} - - -var useXDomainRequest = false; -if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { - useXDomainRequest = true; -} - -function ajaxIE9(method, url, data) { - var promise = new _ParsePromise2.default(); - var xdr = new XDomainRequest(); - xdr.onload = function () { - var response; - try { - response = JSON.parse(xdr.responseText); - } catch (e) { - promise.reject(e); - } - if (response) { - promise.resolve(response); - } - }; - xdr.onerror = xdr.ontimeout = function () { - // Let's fake a real error message. - var fakeResponse = { - responseText: (0, _stringify2.default)({ - code: _ParseError2.default.X_DOMAIN_REQUEST, - error: 'IE\'s XDomainRequest does not supply error info.' - }) - }; - promise.reject(fakeResponse); - }; - xdr.onprogress = function () {}; - xdr.open(method, url); - xdr.send(data); - return promise; -} - -var RESTController = { - ajax: function (method, url, data, headers) { - if (useXDomainRequest) { - return ajaxIE9(method, url, data, headers); - } - - var promise = new _ParsePromise2.default(); - var attempts = 0; - - (function dispatch() { - if (XHR == null) { - throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); - } - var handled = false; - var xhr = new XHR(); - - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4 || handled) { - return; - } - handled = true; - - if (xhr.status >= 200 && xhr.status < 300) { - var response; - try { - response = JSON.parse(xhr.responseText); - } catch (e) { - promise.reject(e.toString()); - } - if (response) { - promise.resolve(response, xhr.status, xhr); - } - } else if (xhr.status >= 500 || xhr.status === 0) { - // retry on 5XX or node-xmlhttprequest error - if (++attempts < _CoreManager2.default.get('REQUEST_ATTEMPT_LIMIT')) { - // Exponentially-growing random delay - var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); - setTimeout(dispatch, delay); - } else if (xhr.status === 0) { - promise.reject('Unable to connect to the Parse API'); - } else { - // After the retry limit is reached, fail - promise.reject(xhr); - } - } else { - promise.reject(xhr); - } - }; - - headers = headers || {}; - if (typeof headers['Content-Type'] !== 'string') { - headers['Content-Type'] = 'text/plain'; // Avoid pre-flight - } - if (_CoreManager2.default.get('IS_NODE')) { - headers['User-Agent'] = 'Parse/' + _CoreManager2.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; - } - - xhr.open(method, url, true); - for (var h in headers) { - xhr.setRequestHeader(h, headers[h]); - } - xhr.send(data); - })(); - - return promise; - }, - request: function (method, path, data, options) { - options = options || {}; - var url = _CoreManager2.default.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += path; - - var payload = {}; - if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') { - for (var k in data) { - payload[k] = data[k]; - } - } - - if (method !== 'POST') { - payload._method = method; - method = 'POST'; - } - - payload._ApplicationId = _CoreManager2.default.get('APPLICATION_ID'); - var jsKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); - if (jsKey) { - payload._JavaScriptKey = jsKey; - } - payload._ClientVersion = _CoreManager2.default.get('VERSION'); - - var useMasterKey = options.useMasterKey; - if (typeof useMasterKey === 'undefined') { - useMasterKey = _CoreManager2.default.get('USE_MASTER_KEY'); - } - if (useMasterKey) { - if (_CoreManager2.default.get('MASTER_KEY')) { - delete payload._JavaScriptKey; - payload._MasterKey = _CoreManager2.default.get('MASTER_KEY'); - } else { - throw new Error('Cannot use the Master Key, it has not been provided.'); - } - } - - if (_CoreManager2.default.get('FORCE_REVOCABLE_SESSION')) { - payload._RevocableSession = '1'; - } - - var installationId = options.installationId; - var installationIdPromise; - if (installationId && typeof installationId === 'string') { - installationIdPromise = _ParsePromise2.default.as(installationId); - } else { - var installationController = _CoreManager2.default.getInstallationController(); - installationIdPromise = installationController.currentInstallationId(); - } - - return installationIdPromise.then(function (iid) { - payload._InstallationId = iid; - var userController = _CoreManager2.default.getUserController(); - if (options && typeof options.sessionToken === 'string') { - return _ParsePromise2.default.as(options.sessionToken); - } else if (userController) { - return userController.currentUserAsync().then(function (user) { - if (user) { - return _ParsePromise2.default.as(user.getSessionToken()); - } - return _ParsePromise2.default.as(null); - }); - } - return _ParsePromise2.default.as(null); - }).then(function (token) { - if (token) { - payload._SessionToken = token; - } - - var payloadString = (0, _stringify2.default)(payload); - - return RESTController.ajax(method, url, payloadString); - }).then(null, function (response) { - // Transform the error into an instance of ParseError by trying to parse - // the error string as JSON - var error; - if (response && response.responseText) { - try { - var errorJSON = JSON.parse(response.responseText); - error = new _ParseError2.default(errorJSON.code, errorJSON.error); - } catch (e) { - // If we fail to parse the error text, that's okay. - error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); - } - } else { - error = new _ParseError2.default(_ParseError2.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify2.default)(response)); - } - - return _ParsePromise2.default.error(error); - }); - }, - _setXHR: function (xhr) { - XHR = xhr; - } -}; - -module.exports = RESTController; \ No newline at end of file diff --git a/lib/browser/SingleInstanceStateController.js b/lib/browser/SingleInstanceStateController.js deleted file mode 100644 index 545dd4c5d..000000000 --- a/lib/browser/SingleInstanceStateController.js +++ /dev/null @@ -1,160 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getState = getState; -exports.initializeState = initializeState; -exports.removeState = removeState; -exports.getServerData = getServerData; -exports.setServerData = setServerData; -exports.getPendingOps = getPendingOps; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.getObjectCache = getObjectCache; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; -exports.enqueueTask = enqueueTask; -exports.clearAllState = clearAllState; -exports.duplicateState = duplicateState; - -var _ObjectStateMutations = require('./ObjectStateMutations'); - -var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -var objectState = {}; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function getState(obj) { - var classData = objectState[obj.className]; - if (classData) { - return classData[obj.id] || null; - } - return null; -} - -function initializeState(obj, initial) { - var state = getState(obj); - if (state) { - return state; - } - if (!objectState[obj.className]) { - objectState[obj.className] = {}; - } - if (!initial) { - initial = ObjectStateMutations.defaultState(); - } - state = objectState[obj.className][obj.id] = initial; - return state; -} - -function removeState(obj) { - var state = getState(obj); - if (state === null) { - return null; - } - delete objectState[obj.className][obj.id]; - return state; -} - -function getServerData(obj) { - var state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -function setServerData(obj, attributes) { - var serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -function getPendingOps(obj) { - var state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -function setPendingOp(obj, attr, op) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -function pushPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -function popPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -function mergeFirstPendingState(obj) { - var pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -function getObjectCache(obj) { - var state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -function estimateAttribute(obj, attr) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -function estimateAttributes(obj) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -function commitServerChanges(obj, changes) { - var state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -function enqueueTask(obj, task) { - var state = initializeState(obj); - return state.tasks.enqueue(task); -} - -function clearAllState() { - objectState = {}; -} - -function duplicateState(source, dest) { - dest.id = source.id; -} \ No newline at end of file diff --git a/lib/browser/Storage.js b/lib/browser/Storage.js deleted file mode 100644 index e5260e608..000000000 --- a/lib/browser/Storage.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = { - async: function () { - var controller = _CoreManager2.default.getStorageController(); - return !!controller.async; - }, - getItem: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.getItem(path); - }, - getItemAsync: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.getItemAsync(path); - } - return _ParsePromise2.default.as(controller.getItem(path)); - }, - setItem: function (path, value) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.setItem(path, value); - }, - setItemAsync: function (path, value) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.setItemAsync(path, value); - } - return _ParsePromise2.default.as(controller.setItem(path, value)); - }, - removeItem: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.removeItem(path); - }, - removeItemAsync: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.removeItemAsync(path); - } - return _ParsePromise2.default.as(controller.removeItem(path)); - }, - generatePath: function (path) { - if (!_CoreManager2.default.get('APPLICATION_ID')) { - throw new Error('You need to call Parse.initialize before using Parse.'); - } - if (typeof path !== 'string') { - throw new Error('Tried to get a Storage path that was not a String.'); - } - if (path[0] === '/') { - path = path.substr(1); - } - return 'Parse/' + _CoreManager2.default.get('APPLICATION_ID') + '/' + path; - }, - _clear: function () { - var controller = _CoreManager2.default.getStorageController(); - if (controller.hasOwnProperty('clear')) { - controller.clear(); - } - } -}; - -_CoreManager2.default.setStorageController(require('./StorageController.browser')); \ No newline at end of file diff --git a/lib/browser/StorageController.browser.js b/lib/browser/StorageController.browser.js deleted file mode 100644 index d372924a0..000000000 --- a/lib/browser/StorageController.browser.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var StorageController = { - async: 0, - - getItem: function (path) { - return localStorage.getItem(path); - }, - setItem: function (path, value) { - try { - localStorage.setItem(path, value); - } catch (e) { - // Quota exceeded, possibly due to Safari Private Browsing mode - } - }, - removeItem: function (path) { - localStorage.removeItem(path); - }, - clear: function () { - localStorage.clear(); - } -}; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/browser/StorageController.default.js b/lib/browser/StorageController.default.js deleted file mode 100644 index 460c1e2ca..000000000 --- a/lib/browser/StorageController.default.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -// When there is no native storage interface, we default to an in-memory map - -var memMap = {}; -var StorageController = { - async: 0, - - getItem: function (path) { - if (memMap.hasOwnProperty(path)) { - return memMap[path]; - } - return null; - }, - setItem: function (path, value) { - memMap[path] = String(value); - }, - removeItem: function (path) { - delete memMap[path]; - }, - clear: function () { - for (var key in memMap) { - if (memMap.hasOwnProperty(key)) { - delete memMap[key]; - } - } - } -}; - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/browser/StorageController.react-native.js b/lib/browser/StorageController.react-native.js deleted file mode 100644 index b92ae6141..000000000 --- a/lib/browser/StorageController.react-native.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _reactNative = require('react-native/Libraries/react-native/react-native.js'); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var StorageController = { - async: 1, - - getItemAsync: function (path) { - var p = new _ParsePromise2.default(); - _reactNative.AsyncStorage.getItem(path, function (err, value) { - if (err) { - p.reject(err); - } else { - p.resolve(value); - } - }); - return p; - }, - setItemAsync: function (path, value) { - var p = new _ParsePromise2.default(); - _reactNative.AsyncStorage.setItem(path, value, function (err) { - if (err) { - p.reject(err); - } else { - p.resolve(value); - } - }); - return p; - }, - removeItemAsync: function (path) { - var p = new _ParsePromise2.default(); - _reactNative.AsyncStorage.removeItem(path, function (err) { - if (err) { - p.reject(err); - } else { - p.resolve(); - } - }); - return p; - }, - clear: function () { - _reactNative.AsyncStorage.clear(); - } -}; -// RN packager nonsense - - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/browser/TaskQueue.js b/lib/browser/TaskQueue.js deleted file mode 100644 index 4bf6bffd0..000000000 --- a/lib/browser/TaskQueue.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var TaskQueue = function () { - function TaskQueue() { - (0, _classCallCheck3.default)(this, TaskQueue); - - this.queue = []; - } - - (0, _createClass3.default)(TaskQueue, [{ - key: 'enqueue', - value: function (task) { - var _this = this; - - var taskComplete = new _ParsePromise2.default(); - this.queue.push({ - task: task, - _completion: taskComplete - }); - if (this.queue.length === 1) { - task().then(function () { - _this._dequeue(); - taskComplete.resolve(); - }, function (error) { - _this._dequeue(); - taskComplete.reject(error); - }); - } - return taskComplete; - } - }, { - key: '_dequeue', - value: function () { - var _this2 = this; - - this.queue.shift(); - if (this.queue.length) { - var next = this.queue[0]; - next.task().then(function () { - _this2._dequeue(); - next._completion.resolve(); - }, function (error) { - _this2._dequeue(); - next._completion.reject(error); - }); - } - } - }]); - return TaskQueue; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = TaskQueue; \ No newline at end of file diff --git a/lib/browser/UniqueInstanceStateController.js b/lib/browser/UniqueInstanceStateController.js deleted file mode 100644 index 12b8ab04d..000000000 --- a/lib/browser/UniqueInstanceStateController.js +++ /dev/null @@ -1,189 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _weakMap = require('babel-runtime/core-js/weak-map'); - -var _weakMap2 = _interopRequireDefault(_weakMap); - -exports.getState = getState; -exports.initializeState = initializeState; -exports.removeState = removeState; -exports.getServerData = getServerData; -exports.setServerData = setServerData; -exports.getPendingOps = getPendingOps; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.getObjectCache = getObjectCache; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; -exports.enqueueTask = enqueueTask; -exports.duplicateState = duplicateState; -exports.clearAllState = clearAllState; - -var _ObjectStateMutations = require('./ObjectStateMutations'); - -var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); - -var _TaskQueue = require('./TaskQueue'); - -var _TaskQueue2 = _interopRequireDefault(_TaskQueue); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var objectState = new _weakMap2.default(); - -function getState(obj) { - var classData = objectState.get(obj); - return classData || null; -} - -function initializeState(obj, initial) { - var state = getState(obj); - if (state) { - return state; - } - if (!initial) { - initial = { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new _TaskQueue2.default(), - existed: false - }; - } - state = initial; - objectState.set(obj, state); - return state; -} - -function removeState(obj) { - var state = getState(obj); - if (state === null) { - return null; - } - objectState.delete(obj); - return state; -} - -function getServerData(obj) { - var state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -function setServerData(obj, attributes) { - var serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -function getPendingOps(obj) { - var state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -function setPendingOp(obj, attr, op) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -function pushPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -function popPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -function mergeFirstPendingState(obj) { - var pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -function getObjectCache(obj) { - var state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -function estimateAttribute(obj, attr) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -function estimateAttributes(obj) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -function commitServerChanges(obj, changes) { - var state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -function enqueueTask(obj, task) { - var state = initializeState(obj); - return state.tasks.enqueue(task); -} - -function duplicateState(source, dest) { - var oldState = initializeState(source); - var newState = initializeState(dest); - for (var key in oldState.serverData) { - newState.serverData[key] = oldState.serverData[key]; - } - for (var index = 0; index < oldState.pendingOps.length; index++) { - for (var _key in oldState.pendingOps[index]) { - newState.pendingOps[index][_key] = oldState.pendingOps[index][_key]; - } - } - for (var _key2 in oldState.objectCache) { - newState.objectCache[_key2] = oldState.objectCache[_key2]; - } - newState.existed = oldState.existed; -} - -function clearAllState() { - objectState = new _weakMap2.default(); -} \ No newline at end of file diff --git a/lib/browser/arrayContainsObject.js b/lib/browser/arrayContainsObject.js deleted file mode 100644 index e9d7949c9..000000000 --- a/lib/browser/arrayContainsObject.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = arrayContainsObject; - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function arrayContainsObject(array, object) { - if (array.indexOf(object) > -1) { - return true; - } - for (var i = 0; i < array.length; i++) { - if (array[i] instanceof _ParseObject2.default && array[i].className === object.className && array[i]._getId() === object._getId()) { - return true; - } - } - return false; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ \ No newline at end of file diff --git a/lib/browser/canBeSerialized.js b/lib/browser/canBeSerialized.js deleted file mode 100644 index e7b7e2282..000000000 --- a/lib/browser/canBeSerialized.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = canBeSerialized; - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function canBeSerialized(obj) { - if (!(obj instanceof _ParseObject2.default)) { - return true; - } - var attributes = obj.attributes; - for (var attr in attributes) { - var val = attributes[attr]; - if (!canBeSerializedHelper(val)) { - return false; - } - } - return true; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function canBeSerializedHelper(value) { - if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { - return true; - } - if (value instanceof _ParseRelation2.default) { - return true; - } - if (value instanceof _ParseObject2.default) { - return !!value.id; - } - if (value instanceof _ParseFile2.default) { - if (value.url()) { - return true; - } - return false; - } - if (Array.isArray(value)) { - for (var i = 0; i < value.length; i++) { - if (!canBeSerializedHelper(value[i])) { - return false; - } - } - return true; - } - for (var k in value) { - if (!canBeSerializedHelper(value[k])) { - return false; - } - } - return true; -} \ No newline at end of file diff --git a/lib/browser/decode.js b/lib/browser/decode.js deleted file mode 100644 index 98a182789..000000000 --- a/lib/browser/decode.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = decode; - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseOp = require('./ParseOp'); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function decode(value) { - if (value === null || (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { - return value; - } - if (Array.isArray(value)) { - var dup = []; - value.forEach(function (v, i) { - dup[i] = decode(v); - }); - return dup; - } - if (typeof value.__op === 'string') { - return (0, _ParseOp.opFromJSON)(value); - } - if (value.__type === 'Pointer' && value.className) { - return _ParseObject2.default.fromJSON(value); - } - if (value.__type === 'Object' && value.className) { - return _ParseObject2.default.fromJSON(value); - } - if (value.__type === 'Relation') { - // The parent and key fields will be populated by the parent - var relation = new _ParseRelation2.default(null, null); - relation.targetClassName = value.className; - return relation; - } - if (value.__type === 'Date') { - return new Date(value.iso); - } - if (value.__type === 'File') { - return _ParseFile2.default.fromJSON(value); - } - if (value.__type === 'GeoPoint') { - return new _ParseGeoPoint2.default({ - latitude: value.latitude, - longitude: value.longitude - }); - } - var copy = {}; - for (var k in value) { - copy[k] = decode(value[k]); - } - return copy; -} \ No newline at end of file diff --git a/lib/browser/encode.js b/lib/browser/encode.js deleted file mode 100644 index 8c3aee6e3..000000000 --- a/lib/browser/encode.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -exports.default = function (value, disallowObjects, forcePointers, seen) { - return encode(value, !!disallowObjects, !!forcePointers, seen || []); -}; - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseOp = require('./ParseOp'); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var toString = Object.prototype.toString; - -function encode(value, disallowObjects, forcePointers, seen) { - if (value instanceof _ParseObject2.default) { - if (disallowObjects) { - throw new Error('Parse Objects not allowed here'); - } - var seenEntry = value.id ? value.className + ':' + value.id : value; - if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || (0, _keys2.default)(value._getServerData()).length < 1) { - return value.toPointer(); - } - seen = seen.concat(seenEntry); - return value._toFullJSON(seen); - } - if (value instanceof _ParseOp.Op || value instanceof _ParseACL2.default || value instanceof _ParseGeoPoint2.default || value instanceof _ParseRelation2.default) { - return value.toJSON(); - } - if (value instanceof _ParseFile2.default) { - if (!value.url()) { - throw new Error('Tried to encode an unsaved file.'); - } - return value.toJSON(); - } - if (toString.call(value) === '[object Date]') { - if (isNaN(value)) { - throw new Error('Tried to encode an invalid date.'); - } - return { __type: 'Date', iso: value.toJSON() }; - } - if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { - return value.source; - } - - if (Array.isArray(value)) { - return value.map(function (v) { - return encode(v, disallowObjects, forcePointers, seen); - }); - } - - if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { - var output = {}; - for (var k in value) { - output[k] = encode(value[k], disallowObjects, forcePointers, seen); - } - return output; - } - - return value; -} \ No newline at end of file diff --git a/lib/browser/equals.js b/lib/browser/equals.js deleted file mode 100644 index 32edcc8a7..000000000 --- a/lib/browser/equals.js +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = equals; - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -function equals(a, b) { - if ((typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== (typeof b === 'undefined' ? 'undefined' : (0, _typeof3.default)(b))) { - return false; - } - - if (!a || (typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== 'object') { - // a is a primitive - return a === b; - } - - if (Array.isArray(a) || Array.isArray(b)) { - if (!Array.isArray(a) || !Array.isArray(b)) { - return false; - } - if (a.length !== b.length) { - return false; - } - for (var i = a.length; i--;) { - if (!equals(a[i], b[i])) { - return false; - } - } - return true; - } - - if (a instanceof _ParseACL2.default || a instanceof _ParseFile2.default || a instanceof _ParseGeoPoint2.default || a instanceof _ParseObject2.default) { - return a.equals(b); - } - - if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) { - return false; - } - for (var k in a) { - if (!equals(a[k], b[k])) { - return false; - } - } - return true; -} \ No newline at end of file diff --git a/lib/browser/escape.js b/lib/browser/escape.js deleted file mode 100644 index 4693baaed..000000000 --- a/lib/browser/escape.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = escape; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var encoded = { - '&': '&', - '<': '<', - '>': '>', - '/': '/', - '\'': ''', - '"': '"' -}; - -function escape(str) { - return str.replace(/[&<>\/'"]/g, function (char) { - return encoded[char]; - }); -} \ No newline at end of file diff --git a/lib/browser/isRevocableSession.js b/lib/browser/isRevocableSession.js deleted file mode 100644 index 92b8230e9..000000000 --- a/lib/browser/isRevocableSession.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = isRevocableSession; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function isRevocableSession(token) { - return token.indexOf('r:') > -1; -} \ No newline at end of file diff --git a/lib/browser/parseDate.js b/lib/browser/parseDate.js deleted file mode 100644 index 48e061b05..000000000 --- a/lib/browser/parseDate.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = parseDate; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function parseDate(iso8601) { - var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); - var match = regexp.exec(iso8601); - if (!match) { - return null; - } - - var year = match[1] || 0; - var month = (match[2] || 1) - 1; - var day = match[3] || 0; - var hour = match[4] || 0; - var minute = match[5] || 0; - var second = match[6] || 0; - var milli = match[8] || 0; - - return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); -} \ No newline at end of file diff --git a/lib/browser/unique.js b/lib/browser/unique.js deleted file mode 100644 index 157b3560a..000000000 --- a/lib/browser/unique.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = unique; - -var _arrayContainsObject = require('./arrayContainsObject'); - -var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function unique(arr) { - var uniques = []; - arr.forEach(function (value) { - if (value instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(uniques, value)) { - uniques.push(value); - } - } else { - if (uniques.indexOf(value) < 0) { - uniques.push(value); - } - } - }); - return uniques; -} \ No newline at end of file diff --git a/lib/browser/unsavedChildren.js b/lib/browser/unsavedChildren.js deleted file mode 100644 index 073efd70b..000000000 --- a/lib/browser/unsavedChildren.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = unsavedChildren; - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Return an array of unsaved children, which are either Parse Objects or Files. - * If it encounters any dirty Objects without Ids, it will throw an exception. - */ -function unsavedChildren(obj, allowDeepUnsaved) { - var encountered = { - objects: {}, - files: [] - }; - var identifier = obj.className + ':' + obj._getId(); - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if ((0, _typeof3.default)(attributes[attr]) === 'object') { - traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); - } - } - var unsaved = []; - for (var id in encountered.objects) { - if (id !== identifier && encountered.objects[id] !== true) { - unsaved.push(encountered.objects[id]); - } - } - return unsaved.concat(encountered.files); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { - if (obj instanceof _ParseObject2.default) { - if (!obj.id && shouldThrow) { - throw new Error('Cannot create a pointer to an unsaved Object.'); - } - var identifier = obj.className + ':' + obj._getId(); - if (!encountered.objects[identifier]) { - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if ((0, _typeof3.default)(attributes[attr]) === 'object') { - traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); - } - } - } - return; - } - if (obj instanceof _ParseFile2.default) { - if (!obj.url() && encountered.files.indexOf(obj) < 0) { - encountered.files.push(obj); - } - return; - } - if (obj instanceof _ParseRelation2.default) { - return; - } - if (Array.isArray(obj)) { - obj.forEach(function (el) { - if ((typeof el === 'undefined' ? 'undefined' : (0, _typeof3.default)(el)) === 'object') { - traverse(el, encountered, shouldThrow, allowDeepUnsaved); - } - }); - } - for (var k in obj) { - if ((0, _typeof3.default)(obj[k]) === 'object') { - traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); - } - } -} \ No newline at end of file diff --git a/lib/node/Analytics.js b/lib/node/Analytics.js deleted file mode 100644 index e5bddf088..000000000 --- a/lib/node/Analytics.js +++ /dev/null @@ -1,89 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.track = track; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Parse.Analytics provides an interface to Parse's logging and analytics - * backend. - * - * @class Parse.Analytics - * @static - */ - -/** - * Tracks the occurrence of a custom event with additional dimensions. - * Parse will store a data point at the time of invocation with the given - * event name. - * - * Dimensions will allow segmentation of the occurrences of this custom - * event. Keys and values should be {@code String}s, and will throw - * otherwise. - * - * To track a user signup along with additional metadata, consider the - * following: - *
                          - * var dimensions = {
                          - *  gender: 'm',
                          - *  source: 'web',
                          - *  dayType: 'weekend'
                          - * };
                          - * Parse.Analytics.track('signup', dimensions);
                          - * 
                          - * - * There is a default limit of 8 dimensions per event tracked. - * - * @method track - * @param {String} name The name of the custom event to report to Parse as - * having happened. - * @param {Object} dimensions The dictionary of information by which to - * segment this event. - * @param {Object} options A Backbone-style callback object. - * @return {Parse.Promise} A promise that is resolved when the round-trip - * to the server completes. - */ -function track(name, dimensions, options) { - name = name || ''; - name = name.replace(/^\s*/, ''); - name = name.replace(/\s*$/, ''); - if (name.length === 0) { - throw new TypeError('A name for the custom event must be provided'); - } - - for (var key in dimensions) { - if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { - throw new TypeError('track() dimensions expects keys and values of type "string".'); - } - } - - options = options || {}; - return _CoreManager2.default.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var DefaultController = { - track: function (name, dimensions) { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); - } -}; - -_CoreManager2.default.setAnalyticsController(DefaultController); \ No newline at end of file diff --git a/lib/node/Cloud.js b/lib/node/Cloud.js deleted file mode 100644 index 72c333750..000000000 --- a/lib/node/Cloud.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.run = run; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains functions for calling and declaring - * cloud functions. - *

                          - * Some functions are only available from Cloud Code. - *

                          - * - * @class Parse.Cloud - * @static - */ - -/** - * Makes a call to a cloud function. - * @method run - * @param {String} name The function name. - * @param {Object} data The parameters to send to the cloud function. - * @param {Object} options A Backbone-style options object - * options.success, if set, should be a function to handle a successful - * call to a cloud function. options.error should be a function that - * handles an error running the cloud function. Both functions are - * optional. Both functions take a single argument. - * @return {Parse.Promise} A promise that will be resolved with the result - * of the function. - */ -function run(name, data, options) { - options = options || {}; - - if (typeof name !== 'string' || name.length === 0) { - throw new TypeError('Cloud function name must be a string.'); - } - - var requestOptions = {}; - if (options.useMasterKey) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.sessionToken) { - requestOptions.sessionToken = options.sessionToken; - } - - return _CoreManager2.default.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var DefaultController = { - run: function (name, data, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - var payload = (0, _encode2.default)(data, true); - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - requestOptions.sessionToken = options.sessionToken; - } - - var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); - - return request.then(function (res) { - var decoded = (0, _decode2.default)(res); - if (decoded && decoded.hasOwnProperty('result')) { - return _ParsePromise2.default.as(decoded.result); - } - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); - })._thenRunCallbacks(options); - } -}; - -_CoreManager2.default.setCloudController(DefaultController); \ No newline at end of file diff --git a/lib/node/CoreManager.js b/lib/node/CoreManager.js deleted file mode 100644 index 20d66a5f1..000000000 --- a/lib/node/CoreManager.js +++ /dev/null @@ -1,161 +0,0 @@ -'use strict'; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var config = { - // Defaults - IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, - REQUEST_ATTEMPT_LIMIT: 5, - SERVER_URL: 'https://api.parse.com/1', - LIVEQUERY_SERVER_URL: null, - VERSION: 'js' + '1.9.2', - APPLICATION_ID: null, - JAVASCRIPT_KEY: null, - MASTER_KEY: null, - USE_MASTER_KEY: false, - PERFORM_USER_REWRITE: true, - FORCE_REVOCABLE_SESSION: false -}; - -function requireMethods(name, methods, controller) { - methods.forEach(function (func) { - if (typeof controller[func] !== 'function') { - throw new Error(name + ' must implement ' + func + '()'); - } - }); -} - -module.exports = { - get: function (key) { - if (config.hasOwnProperty(key)) { - return config[key]; - } - throw new Error('Configuration key not found: ' + key); - }, - - set: function (key, value) { - config[key] = value; - }, - - /* Specialized Controller Setters/Getters */ - - setAnalyticsController: function (controller) { - requireMethods('AnalyticsController', ['track'], controller); - config['AnalyticsController'] = controller; - }, - getAnalyticsController: function () { - return config['AnalyticsController']; - }, - setCloudController: function (controller) { - requireMethods('CloudController', ['run'], controller); - config['CloudController'] = controller; - }, - getCloudController: function () { - return config['CloudController']; - }, - setConfigController: function (controller) { - requireMethods('ConfigController', ['current', 'get'], controller); - config['ConfigController'] = controller; - }, - getConfigController: function () { - return config['ConfigController']; - }, - setFileController: function (controller) { - requireMethods('FileController', ['saveFile', 'saveBase64'], controller); - config['FileController'] = controller; - }, - getFileController: function () { - return config['FileController']; - }, - setInstallationController: function (controller) { - requireMethods('InstallationController', ['currentInstallationId'], controller); - config['InstallationController'] = controller; - }, - getInstallationController: function () { - return config['InstallationController']; - }, - setObjectController: function (controller) { - requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); - config['ObjectController'] = controller; - }, - getObjectController: function () { - return config['ObjectController']; - }, - setObjectStateController: function (controller) { - requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); - - config['ObjectStateController'] = controller; - }, - getObjectStateController: function () { - return config['ObjectStateController']; - }, - setPushController: function (controller) { - requireMethods('PushController', ['send'], controller); - config['PushController'] = controller; - }, - getPushController: function () { - return config['PushController']; - }, - setQueryController: function (controller) { - requireMethods('QueryController', ['find'], controller); - config['QueryController'] = controller; - }, - getQueryController: function () { - return config['QueryController']; - }, - setRESTController: function (controller) { - requireMethods('RESTController', ['request', 'ajax'], controller); - config['RESTController'] = controller; - }, - getRESTController: function () { - return config['RESTController']; - }, - setSessionController: function (controller) { - requireMethods('SessionController', ['getSession'], controller); - config['SessionController'] = controller; - }, - getSessionController: function () { - return config['SessionController']; - }, - setStorageController: function (controller) { - if (controller.async) { - requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); - } else { - requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); - } - config['StorageController'] = controller; - }, - getStorageController: function () { - return config['StorageController']; - }, - setUserController: function (controller) { - requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); - config['UserController'] = controller; - }, - getUserController: function () { - return config['UserController']; - }, - setLiveQueryController: function (controller) { - requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); - config['LiveQueryController'] = controller; - }, - getLiveQueryController: function () { - return config['LiveQueryController']; - }, - setHooksController: function (controller) { - requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); - config['HooksController'] = controller; - }, - getHooksController: function () { - return config['HooksController']; - } -}; \ No newline at end of file diff --git a/lib/node/EventEmitter.js b/lib/node/EventEmitter.js deleted file mode 100644 index e9414f0bf..000000000 --- a/lib/node/EventEmitter.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This is a simple wrapper to unify EventEmitter implementations across platforms. - */ - -module.exports = require('events').EventEmitter; -var EventEmitter; \ No newline at end of file diff --git a/lib/node/FacebookUtils.js b/lib/node/FacebookUtils.js deleted file mode 100644 index bb8b7ef51..000000000 --- a/lib/node/FacebookUtils.js +++ /dev/null @@ -1,243 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _parseDate = require('./parseDate'); - -var _parseDate2 = _interopRequireDefault(_parseDate); - -var _ParseUser = require('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * -weak - */ - -var PUBLIC_KEY = "*"; - -var initialized = false; -var requestedPermissions; -var initOptions; -var provider = { - authenticate: function (options) { - var _this = this; - - if (typeof FB === 'undefined') { - options.error(this, 'Facebook SDK not found.'); - } - FB.login(function (response) { - if (response.authResponse) { - if (options.success) { - options.success(_this, { - id: response.authResponse.userID, - access_token: response.authResponse.accessToken, - expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() - }); - } - } else { - if (options.error) { - options.error(_this, response); - } - } - }, { - scope: requestedPermissions - }); - }, - restoreAuthentication: function (authData) { - if (authData) { - var expiration = (0, _parseDate2.default)(authData.expiration_date); - var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; - - var authResponse = { - userID: authData.id, - accessToken: authData.access_token, - expiresIn: expiresIn - }; - var newOptions = {}; - if (initOptions) { - for (var key in initOptions) { - newOptions[key] = initOptions[key]; - } - } - newOptions.authResponse = authResponse; - - // Suppress checks for login status from the browser. - newOptions.status = false; - - // If the user doesn't match the one known by the FB SDK, log out. - // Most of the time, the users will match -- it's only in cases where - // the FB SDK knows of a different user than the one being restored - // from a Parse User that logged in with username/password. - var existingResponse = FB.getAuthResponse(); - if (existingResponse && existingResponse.userID !== authResponse.userID) { - FB.logout(); - } - - FB.init(newOptions); - } - return true; - }, - getAuthType: function () { - return 'facebook'; - }, - deauthenticate: function () { - this.restoreAuthentication(null); - } -}; - -/** - * Provides a set of utilities for using Parse with Facebook. - * @class Parse.FacebookUtils - * @static - */ -var FacebookUtils = { - /** - * Initializes Parse Facebook integration. Call this function after you - * have loaded the Facebook Javascript SDK with the same parameters - * as you would pass to - * - * FB.init(). Parse.FacebookUtils will invoke FB.init() for you - * with these arguments. - * - * @method init - * @param {Object} options Facebook options argument as described here: - * - * FB.init(). The status flag will be coerced to 'false' because it - * interferes with Parse Facebook integration. Call FB.getLoginStatus() - * explicitly if this behavior is required by your application. - */ - init: function (options) { - if (typeof FB === 'undefined') { - throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); - } - initOptions = {}; - if (options) { - for (var key in options) { - initOptions[key] = options[key]; - } - } - if (initOptions.status && typeof console !== 'undefined') { - var warn = console.warn || console.log || function () {}; - warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); - } - initOptions.status = false; - FB.init(initOptions); - _ParseUser2.default._registerAuthenticationProvider(provider); - initialized = true; - }, - - /** - * Gets whether the user has their account linked to Facebook. - * - * @method isLinked - * @param {Parse.User} user User to check for a facebook link. - * The user must be logged in on this device. - * @return {Boolean} true if the user has their account - * linked to Facebook. - */ - isLinked: function (user) { - return user._isLinked('facebook'); - }, - - /** - * Logs in a user using Facebook. This method delegates to the Facebook - * SDK to authenticate the user, and then automatically logs in (or - * creates, in the case where it is a new user) a Parse.User. - * - * @method logIn - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - logIn: function (permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling logIn.'); - } - requestedPermissions = permissions; - return _ParseUser2.default._logInWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return _ParseUser2.default._logInWith('facebook', newOptions); - } - }, - - /** - * Links Facebook to an existing PFUser. This method delegates to the - * Facebook SDK to authenticate the user, and then automatically links - * the account to the Parse.User. - * - * @method link - * @param {Parse.User} user User to link to Facebook. This must be the - * current user. - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - link: function (user, permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling link.'); - } - requestedPermissions = permissions; - return user._linkWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return user._linkWith('facebook', newOptions); - } - }, - - /** - * Unlinks the Parse.User from a Facebook account. - * - * @method unlink - * @param {Parse.User} user User to unlink from Facebook. This must be the - * current user. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - unlink: function (user, options) { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling unlink.'); - } - return user._unlinkFrom('facebook', options); - } -}; - -exports.default = FacebookUtils; \ No newline at end of file diff --git a/lib/node/InstallationController.js b/lib/node/InstallationController.js deleted file mode 100644 index 7b01e3cad..000000000 --- a/lib/node/InstallationController.js +++ /dev/null @@ -1,64 +0,0 @@ -'use strict'; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var iidCache = null; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function hexOctet() { - return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); -} - -function generateId() { - return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); -} - -var InstallationController = { - currentInstallationId: function () { - if (typeof iidCache === 'string') { - return _ParsePromise2.default.as(iidCache); - } - var path = _Storage2.default.generatePath('installationId'); - return _Storage2.default.getItemAsync(path).then(function (iid) { - if (!iid) { - iid = generateId(); - return _Storage2.default.setItemAsync(path, iid).then(function () { - iidCache = iid; - return iid; - }); - } - iidCache = iid; - return iid; - }); - }, - _clearCache: function () { - iidCache = null; - }, - _setInstallationIdCache: function (iid) { - iidCache = iid; - } -}; - -module.exports = InstallationController; \ No newline at end of file diff --git a/lib/node/LiveQueryClient.js b/lib/node/LiveQueryClient.js deleted file mode 100644 index e0420323f..000000000 --- a/lib/node/LiveQueryClient.js +++ /dev/null @@ -1,595 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getIterator2 = require('babel-runtime/core-js/get-iterator'); - -var _getIterator3 = _interopRequireDefault(_getIterator2); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _map = require('babel-runtime/core-js/map'); - -var _map2 = _interopRequireDefault(_map); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _EventEmitter2 = require('./EventEmitter'); - -var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _LiveQuerySubscription = require('./LiveQuerySubscription'); - -var _LiveQuerySubscription2 = _interopRequireDefault(_LiveQuerySubscription); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -// The LiveQuery client inner state -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -var CLIENT_STATE = { - INITIALIZED: 'initialized', - CONNECTING: 'connecting', - CONNECTED: 'connected', - CLOSED: 'closed', - RECONNECTING: 'reconnecting', - DISCONNECTED: 'disconnected' -}; - -// The event type the LiveQuery client should sent to server -var OP_TYPES = { - CONNECT: 'connect', - SUBSCRIBE: 'subscribe', - UNSUBSCRIBE: 'unsubscribe', - ERROR: 'error' -}; - -// The event we get back from LiveQuery server -var OP_EVENTS = { - CONNECTED: 'connected', - SUBSCRIBED: 'subscribed', - UNSUBSCRIBED: 'unsubscribed', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -// The event the LiveQuery client should emit -var CLIENT_EMMITER_TYPES = { - CLOSE: 'close', - ERROR: 'error', - OPEN: 'open' -}; - -// The event the LiveQuery subscription should emit -var SUBSCRIPTION_EMMITER_TYPES = { - OPEN: 'open', - CLOSE: 'close', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -var generateInterval = function (k) { - return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; -}; - -/** - * Creates a new LiveQueryClient. - * Extends events.EventEmitter - * cloud functions. - * - * A wrapper of a standard WebSocket client. We add several useful methods to - * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. - * - * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries - * to connect to the LiveQuery server - * - * @class Parse.LiveQueryClient - * @constructor - * @param {Object} options - * @param {string} options.applicationId - applicationId of your Parse app - * @param {string} options.serverURL - the URL of your LiveQuery server - * @param {string} options.javascriptKey (optional) - * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) - * @param {string} options.sessionToken (optional) - * - * - * We expose three events to help you monitor the status of the LiveQueryClient. - * - *
                          - * let Parse = require('parse/node');
                          - * let LiveQueryClient = Parse.LiveQueryClient;
                          - * let client = new LiveQueryClient({
                          - *   applicationId: '',
                          - *   serverURL: '',
                          - *   javascriptKey: '',
                          - *   masterKey: ''
                          - *  });
                          - * 
                          - * - * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - *
                          - * client.on('open', () => {
                          - * 
                          - * });
                          - * - * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - *
                          - * client.on('close', () => {
                          - * 
                          - * });
                          - * - * Error - When some network error or LiveQuery server error happens, you'll get this event. - *
                          - * client.on('error', (error) => {
                          - * 
                          - * });
                          - * - * - */ - -var LiveQueryClient = function (_EventEmitter) { - (0, _inherits3.default)(LiveQueryClient, _EventEmitter); - - function LiveQueryClient(_ref) { - var applicationId = _ref.applicationId, - serverURL = _ref.serverURL, - javascriptKey = _ref.javascriptKey, - masterKey = _ref.masterKey, - sessionToken = _ref.sessionToken; - (0, _classCallCheck3.default)(this, LiveQueryClient); - - var _this = (0, _possibleConstructorReturn3.default)(this, (LiveQueryClient.__proto__ || (0, _getPrototypeOf2.default)(LiveQueryClient)).call(this)); - - if (!serverURL || serverURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - _this.reconnectHandle = null; - _this.attempts = 1;; - _this.id = 0; - _this.requestId = 1; - _this.serverURL = serverURL; - _this.applicationId = applicationId; - _this.javascriptKey = javascriptKey; - _this.masterKey = masterKey; - _this.sessionToken = sessionToken; - _this.connectPromise = new _ParsePromise2.default(); - _this.subscriptions = new _map2.default(); - _this.state = CLIENT_STATE.INITIALIZED; - return _this; - } - - (0, _createClass3.default)(LiveQueryClient, [{ - key: 'shouldOpen', - value: function () { - return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; - } - - /** - * Subscribes to a ParseQuery - * - * If you provide the sessionToken, when the LiveQuery server gets ParseObject's - * updates from parse server, it'll try to check whether the sessionToken fulfills - * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose - * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol - * here for more details. The subscription you get is the same subscription you get - * from our Standard API. - * - * @method subscribe - * @param {Object} query - the ParseQuery you want to subscribe to - * @param {string} sessionToken (optional) - * @return {Object} subscription - */ - - }, { - key: 'subscribe', - value: function (query, sessionToken) { - var _this2 = this; - - if (!query) { - return; - } - var where = query.toJSON().where; - var className = query.className; - var subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: this.requestId, - query: { - className: className, - where: where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - var subscription = new _LiveQuerySubscription2.default(this.requestId, query, sessionToken); - this.subscriptions.set(this.requestId, subscription); - this.requestId += 1; - this.connectPromise.then(function () { - _this2.socket.send((0, _stringify2.default)(subscribeRequest)); - }); - - // adding listener so process does not crash - // best practice is for developer to register their own listener - subscription.on('error', function () {}); - - return subscription; - } - - /** - * After calling unsubscribe you'll stop receiving events from the subscription object. - * - * @method unsubscribe - * @param {Object} subscription - subscription you would like to unsubscribe from. - */ - - }, { - key: 'unsubscribe', - value: function (subscription) { - var _this3 = this; - - if (!subscription) { - return; - } - - this.subscriptions.delete(subscription.id); - var unsubscribeRequest = { - op: OP_TYPES.UNSUBSCRIBE, - requestId: subscription.id - }; - this.connectPromise.then(function () { - _this3.socket.send((0, _stringify2.default)(unsubscribeRequest)); - }); - } - - /** - * After open is called, the LiveQueryClient will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ - - }, { - key: 'open', - value: function () { - var _this4 = this; - - var WebSocketImplementation = this._getWebSocketImplementation(); - if (!WebSocketImplementation) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); - return; - } - - if (this.state !== CLIENT_STATE.RECONNECTING) { - this.state = CLIENT_STATE.CONNECTING; - } - - // Get WebSocket implementation - this.socket = new WebSocketImplementation(this.serverURL); - - // Bind WebSocket callbacks - this.socket.onopen = function () { - _this4._handleWebSocketOpen(); - }; - - this.socket.onmessage = function (event) { - _this4._handleWebSocketMessage(event); - }; - - this.socket.onclose = function () { - _this4._handleWebSocketClose(); - }; - - this.socket.onerror = function (error) { - _this4._handleWebSocketError(error); - }; - } - }, { - key: 'resubscribe', - value: function () { - var _this5 = this; - - this.subscriptions.forEach(function (subscription, requestId) { - var query = subscription.query; - var where = query.toJSON().where; - var className = query.className; - var sessionToken = subscription.sessionToken; - var subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: requestId, - query: { - className: className, - where: where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - _this5.connectPromise.then(function () { - _this5.socket.send((0, _stringify2.default)(subscribeRequest)); - }); - }); - } - - /** - * This method will close the WebSocket connection to this LiveQueryClient, - * cancel the auto reconnect and unsubscribe all subscriptions based on it. - * - * @method close - */ - - }, { - key: 'close', - value: function () { - if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.DISCONNECTED; - this.socket.close(); - // Notify each subscription about the close - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = (0, _getIterator3.default)(this.subscriptions.values()), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var subscription = _step.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - this._handleReset(); - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - } - }, { - key: '_getWebSocketImplementation', - value: function () { - return require('ws'); - } - - // ensure we start with valid state if connect is called again after close - - }, { - key: '_handleReset', - value: function () { - this.attempts = 1;; - this.id = 0; - this.requestId = 1; - this.connectPromise = new _ParsePromise2.default(); - this.subscriptions = new _map2.default(); - } - }, { - key: '_handleWebSocketOpen', - value: function () { - this.attempts = 1; - var connectRequest = { - op: OP_TYPES.CONNECT, - applicationId: this.applicationId, - javascriptKey: this.javascriptKey, - masterKey: this.masterKey, - sessionToken: this.sessionToken - }; - this.socket.send((0, _stringify2.default)(connectRequest)); - } - }, { - key: '_handleWebSocketMessage', - value: function (event) { - var data = event.data; - if (typeof data === 'string') { - data = JSON.parse(data); - } - var subscription = null; - if (data.requestId) { - subscription = this.subscriptions.get(data.requestId); - } - switch (data.op) { - case OP_EVENTS.CONNECTED: - if (this.state === CLIENT_STATE.RECONNECTING) { - this.resubscribe(); - } - this.emit(CLIENT_EMMITER_TYPES.OPEN); - this.id = data.clientId; - this.connectPromise.resolve(); - this.state = CLIENT_STATE.CONNECTED; - break; - case OP_EVENTS.SUBSCRIBED: - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); - } - break; - case OP_EVENTS.ERROR: - if (data.requestId) { - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); - } - } else { - this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); - } - break; - case OP_EVENTS.UNSUBSCRIBED: - // We have already deleted subscription in unsubscribe(), do nothing here - break; - default: - // create, update, enter, leave, delete cases - var className = data.object.className; - // Delete the extrea __type and className fields during transfer to full JSON - delete data.object.__type; - delete data.object.className; - var parseObject = new _ParseObject2.default(className); - parseObject._finishFetch(data.object); - if (!subscription) { - break; - } - subscription.emit(data.op, parseObject); - } - } - }, { - key: '_handleWebSocketClose', - value: function () { - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.CLOSED; - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - // Notify each subscription about the close - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = (0, _getIterator3.default)(this.subscriptions.values()), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var subscription = _step2.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - this._handleReconnect(); - } - }, { - key: '_handleWebSocketError', - value: function (error) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, error); - var _iteratorNormalCompletion3 = true; - var _didIteratorError3 = false; - var _iteratorError3 = undefined; - - try { - for (var _iterator3 = (0, _getIterator3.default)(this.subscriptions.values()), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) { - var subscription = _step3.value; - - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); - } - } catch (err) { - _didIteratorError3 = true; - _iteratorError3 = err; - } finally { - try { - if (!_iteratorNormalCompletion3 && _iterator3.return) { - _iterator3.return(); - } - } finally { - if (_didIteratorError3) { - throw _iteratorError3; - } - } - } - - this._handleReconnect(); - } - }, { - key: '_handleReconnect', - value: function () { - var _this6 = this; - - // if closed or currently reconnecting we stop attempting to reconnect - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - - this.state = CLIENT_STATE.RECONNECTING; - var time = generateInterval(this.attempts); - - // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. - // we're unable to distinguish different between close/error when we're unable to reconnect therefore - // we try to reonnect in both cases - // server side ws and browser WebSocket behave differently in when close/error get triggered - - if (this.reconnectHandle) { - clearTimeout(this.reconnectHandle); - } - - this.reconnectHandle = setTimeout(function () { - _this6.attempts++; - _this6.connectPromise = new _ParsePromise2.default(); - _this6.open(); - }.bind(this), time); - } - }]); - return LiveQueryClient; -}(_EventEmitter3.default); - -exports.default = LiveQueryClient; \ No newline at end of file diff --git a/lib/node/LiveQuerySubscription.js b/lib/node/LiveQuerySubscription.js deleted file mode 100644 index 4078b65d5..000000000 --- a/lib/node/LiveQuerySubscription.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _EventEmitter2 = require('./EventEmitter'); - -var _EventEmitter3 = _interopRequireDefault(_EventEmitter2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new LiveQuery Subscription. - * Extends events.EventEmitter - * cloud functions. - * - * @constructor - * @param {string} id - subscription id - * @param {string} query - query to subscribe to - * @param {string} sessionToken - optional session token - * - *

                          Open Event - When you call query.subscribe(), we send a subscribe request to - * the LiveQuery server, when we get the confirmation from the LiveQuery server, - * this event will be emitted. When the client loses WebSocket connection to the - * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we - * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, - * you'll also get this event. - * - *

                          - * subscription.on('open', () => {
                          - * 
                          - * });

                          - * - *

                          Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, - * you'll get this event. The object is the ParseObject which is created. - * - *

                          - * subscription.on('create', (object) => {
                          - * 
                          - * });

                          - * - *

                          Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe - * is updated (The ParseObject fulfills the ParseQuery before and after changes), - * you'll get this event. The object is the ParseObject which is updated. - * Its content is the latest value of the ParseObject. - * - *

                          - * subscription.on('update', (object) => {
                          - * 
                          - * });

                          - * - *

                          Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery - * but its new value fulfills the ParseQuery, you'll get this event. The object is the - * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                          - * subscription.on('enter', (object) => {
                          - * 
                          - * });

                          - * - * - *

                          Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value - * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject - * which leaves the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                          - * subscription.on('leave', (object) => {
                          - * 
                          - * });

                          - * - * - *

                          Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll - * get this event. The object is the ParseObject which is deleted. - * - *

                          - * subscription.on('delete', (object) => {
                          - * 
                          - * });

                          - * - * - *

                          Close Event - When the client loses the WebSocket connection to the LiveQuery - * server and we stop receiving events, you'll get this event. - * - *

                          - * subscription.on('close', () => {
                          - * 
                          - * });

                          - * - * - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -var Subscription = function (_EventEmitter) { - (0, _inherits3.default)(Subscription, _EventEmitter); - - function Subscription(id, query, sessionToken) { - (0, _classCallCheck3.default)(this, Subscription); - - var _this2 = (0, _possibleConstructorReturn3.default)(this, (Subscription.__proto__ || (0, _getPrototypeOf2.default)(Subscription)).call(this)); - - _this2.id = id; - _this2.query = query; - _this2.sessionToken = sessionToken; - return _this2; - } - - /** - * @method unsubscribe - */ - - (0, _createClass3.default)(Subscription, [{ - key: 'unsubscribe', - value: function () { - var _this3 = this; - - var _this = this; - _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient().then(function (liveQueryClient) { - liveQueryClient.unsubscribe(_this); - _this.emit('close'); - _this3.resolve(); - }); - } - }]); - return Subscription; -}(_EventEmitter3.default); - -exports.default = Subscription; \ No newline at end of file diff --git a/lib/node/ObjectStateMutations.js b/lib/node/ObjectStateMutations.js deleted file mode 100644 index b476a0e2f..000000000 --- a/lib/node/ObjectStateMutations.js +++ /dev/null @@ -1,165 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.defaultState = defaultState; -exports.setServerData = setServerData; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _TaskQueue = require('./TaskQueue'); - -var _TaskQueue2 = _interopRequireDefault(_TaskQueue); - -var _ParseOp = require('./ParseOp'); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function defaultState() { - return { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new _TaskQueue2.default(), - existed: false - }; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function setServerData(serverData, attributes) { - for (var _attr in attributes) { - if (typeof attributes[_attr] !== 'undefined') { - serverData[_attr] = attributes[_attr]; - } else { - delete serverData[_attr]; - } - } -} - -function setPendingOp(pendingOps, attr, op) { - var last = pendingOps.length - 1; - if (op) { - pendingOps[last][attr] = op; - } else { - delete pendingOps[last][attr]; - } -} - -function pushPendingState(pendingOps) { - pendingOps.push({}); -} - -function popPendingState(pendingOps) { - var first = pendingOps.shift(); - if (!pendingOps.length) { - pendingOps[0] = {}; - } - return first; -} - -function mergeFirstPendingState(pendingOps) { - var first = popPendingState(pendingOps); - var next = pendingOps[0]; - for (var _attr2 in first) { - if (next[_attr2] && first[_attr2]) { - var merged = next[_attr2].mergeWith(first[_attr2]); - if (merged) { - next[_attr2] = merged; - } - } else { - next[_attr2] = first[_attr2]; - } - } -} - -function estimateAttribute(serverData, pendingOps, className, id, attr) { - var value = serverData[attr]; - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i][attr]) { - if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { - if (id) { - value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); - } - } else { - value = pendingOps[i][attr].applyTo(value); - } - } - } - return value; -} - -function estimateAttributes(serverData, pendingOps, className, id) { - var data = {}; - var attr = void 0; - for (attr in serverData) { - data[attr] = serverData[attr]; - } - for (var i = 0; i < pendingOps.length; i++) { - for (attr in pendingOps[i]) { - if (pendingOps[i][attr] instanceof _ParseOp.RelationOp) { - if (id) { - data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); - } - } else { - data[attr] = pendingOps[i][attr].applyTo(data[attr]); - } - } - } - return data; -} - -function commitServerChanges(serverData, objectCache, changes) { - for (var _attr3 in changes) { - var val = changes[_attr3]; - serverData[_attr3] = val; - if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof _ParseObject2.default) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { - var json = (0, _encode2.default)(val, false, true); - objectCache[_attr3] = (0, _stringify2.default)(json); - } - } -} \ No newline at end of file diff --git a/lib/node/Parse.js b/lib/node/Parse.js deleted file mode 100644 index 280cd4015..000000000 --- a/lib/node/Parse.js +++ /dev/null @@ -1,190 +0,0 @@ -'use strict'; - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _InstallationController = require('./InstallationController'); - -var _InstallationController2 = _interopRequireDefault(_InstallationController); - -var _ParseOp = require('./ParseOp'); - -var ParseOp = _interopRequireWildcard(_ParseOp); - -var _RESTController = require('./RESTController'); - -var _RESTController2 = _interopRequireDefault(_RESTController); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains all Parse API classes and functions. - * @class Parse - * @static - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var Parse = { - /** - * Call this method first to set up your authentication tokens for Parse. - * You can get your keys from the Data Browser on parse.com. - * @method initialize - * @param {String} applicationId Your Parse Application ID. - * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) - * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) - * @static - */ - initialize: function (applicationId, javaScriptKey) { - Parse._initialize(applicationId, javaScriptKey); - }, - _initialize: function (applicationId, javaScriptKey, masterKey) { - _CoreManager2.default.set('APPLICATION_ID', applicationId); - _CoreManager2.default.set('JAVASCRIPT_KEY', javaScriptKey); - _CoreManager2.default.set('MASTER_KEY', masterKey); - _CoreManager2.default.set('USE_MASTER_KEY', false); - } -}; - -/** These legacy setters may eventually be deprecated **/ -Object.defineProperty(Parse, 'applicationId', { - get: function () { - return _CoreManager2.default.get('APPLICATION_ID'); - }, - set: function (value) { - _CoreManager2.default.set('APPLICATION_ID', value); - } -}); -Object.defineProperty(Parse, 'javaScriptKey', { - get: function () { - return _CoreManager2.default.get('JAVASCRIPT_KEY'); - }, - set: function (value) { - _CoreManager2.default.set('JAVASCRIPT_KEY', value); - } -}); -Object.defineProperty(Parse, 'masterKey', { - get: function () { - return _CoreManager2.default.get('MASTER_KEY'); - }, - set: function (value) { - _CoreManager2.default.set('MASTER_KEY', value); - } -}); -Object.defineProperty(Parse, 'serverURL', { - get: function () { - return _CoreManager2.default.get('SERVER_URL'); - }, - set: function (value) { - _CoreManager2.default.set('SERVER_URL', value); - } -}); -Object.defineProperty(Parse, 'liveQueryServerURL', { - get: function () { - return _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); - }, - set: function (value) { - _CoreManager2.default.set('LIVEQUERY_SERVER_URL', value); - } -}); -/** End setters **/ - -Parse.ACL = require('./ParseACL').default; -Parse.Analytics = require('./Analytics'); -Parse.Cloud = require('./Cloud'); -Parse.CoreManager = require('./CoreManager'); -Parse.Config = require('./ParseConfig').default; -Parse.Error = require('./ParseError').default; -Parse.FacebookUtils = require('./FacebookUtils').default; -Parse.File = require('./ParseFile').default; -Parse.GeoPoint = require('./ParseGeoPoint').default; -Parse.Installation = require('./ParseInstallation').default; -Parse.Object = require('./ParseObject').default; -Parse.Op = { - Set: ParseOp.SetOp, - Unset: ParseOp.UnsetOp, - Increment: ParseOp.IncrementOp, - Add: ParseOp.AddOp, - Remove: ParseOp.RemoveOp, - AddUnique: ParseOp.AddUniqueOp, - Relation: ParseOp.RelationOp -}; -Parse.Promise = require('./ParsePromise').default; -Parse.Push = require('./Push'); -Parse.Query = require('./ParseQuery').default; -Parse.Relation = require('./ParseRelation').default; -Parse.Role = require('./ParseRole').default; -Parse.Session = require('./ParseSession').default; -Parse.Storage = require('./Storage'); -Parse.User = require('./ParseUser').default; -Parse.LiveQuery = require('./ParseLiveQuery').default; -Parse.LiveQueryClient = require('./LiveQueryClient').default; - -Parse._request = function () { - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return _CoreManager2.default.getRESTController().request.apply(null, args); -}; -Parse._ajax = function () { - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return _CoreManager2.default.getRESTController().ajax.apply(null, args); -}; -// We attempt to match the signatures of the legacy versions of these methods -Parse._decode = function (_, value) { - return (0, _decode2.default)(value); -}; -Parse._encode = function (value, _, disallowObjects) { - return (0, _encode2.default)(value, disallowObjects); -}; -Parse._getInstallationId = function () { - return _CoreManager2.default.getInstallationController().currentInstallationId(); -}; - -_CoreManager2.default.setInstallationController(_InstallationController2.default); -_CoreManager2.default.setRESTController(_RESTController2.default); - -Parse.initialize = Parse._initialize; -Parse.Cloud = Parse.Cloud || {}; -Parse.Cloud.useMasterKey = function () { - _CoreManager2.default.set('USE_MASTER_KEY', true); -}; -Parse.Hooks = require('./ParseHooks'); - -// For legacy requires, of the form `var Parse = require('parse').Parse` -Parse.Parse = Parse; - -module.exports = Parse; \ No newline at end of file diff --git a/lib/node/ParseACL.js b/lib/node/ParseACL.js deleted file mode 100644 index 2aa232c18..000000000 --- a/lib/node/ParseACL.js +++ /dev/null @@ -1,406 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParseRole = require('./ParseRole'); - -var _ParseRole2 = _interopRequireDefault(_ParseRole); - -var _ParseUser = require('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var PUBLIC_KEY = '*'; - -/** - * Creates a new ACL. - * If no argument is given, the ACL has no permissions for anyone. - * If the argument is a Parse.User, the ACL will have read and write - * permission for only that user. - * If the argument is any other JSON object, that object will be interpretted - * as a serialized ACL created with toJSON(). - * @class Parse.ACL - * @constructor - * - *

                          An ACL, or Access Control List can be added to any - * Parse.Object to restrict access to only a subset of users - * of your application.

                          - */ - -var ParseACL = function () { - function ParseACL(arg1) { - (0, _classCallCheck3.default)(this, ParseACL); - - this.permissionsById = {}; - if (arg1 && (typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { - if (arg1 instanceof _ParseUser2.default) { - this.setReadAccess(arg1, true); - this.setWriteAccess(arg1, true); - } else { - for (var userId in arg1) { - var accessList = arg1[userId]; - if (typeof userId !== 'string') { - throw new TypeError('Tried to create an ACL with an invalid user id.'); - } - this.permissionsById[userId] = {}; - for (var permission in accessList) { - var allowed = accessList[permission]; - if (permission !== 'read' && permission !== 'write') { - throw new TypeError('Tried to create an ACL with an invalid permission type.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('Tried to create an ACL with an invalid permission value.'); - } - this.permissionsById[userId][permission] = allowed; - } - } - } - } else if (typeof arg1 === 'function') { - throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); - } - } - - /** - * Returns a JSON-encoded version of the ACL. - * @method toJSON - * @return {Object} - */ - - (0, _createClass3.default)(ParseACL, [{ - key: 'toJSON', - value: function () { - var permissions = {}; - for (var p in this.permissionsById) { - permissions[p] = this.permissionsById[p]; - } - return permissions; - } - - /** - * Returns whether this ACL is equal to another object - * @method equals - * @param other The other object to compare to - * @return {Boolean} - */ - - }, { - key: 'equals', - value: function (other) { - if (!(other instanceof ParseACL)) { - return false; - } - var users = (0, _keys2.default)(this.permissionsById); - var otherUsers = (0, _keys2.default)(other.permissionsById); - if (users.length !== otherUsers.length) { - return false; - } - for (var u in this.permissionsById) { - if (!other.permissionsById[u]) { - return false; - } - if (this.permissionsById[u].read !== other.permissionsById[u].read) { - return false; - } - if (this.permissionsById[u].write !== other.permissionsById[u].write) { - return false; - } - } - return true; - } - }, { - key: '_setAccess', - value: function (accessType, userId, allowed) { - if (userId instanceof _ParseUser2.default) { - userId = userId.id; - } else if (userId instanceof _ParseRole2.default) { - var name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - if (typeof userId !== 'string') { - throw new TypeError('userId must be a string.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('allowed must be either true or false.'); - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - if (!allowed) { - // The user already doesn't have this permission, so no action is needed - return; - } else { - permissions = {}; - this.permissionsById[userId] = permissions; - } - } - - if (allowed) { - this.permissionsById[userId][accessType] = true; - } else { - delete permissions[accessType]; - if ((0, _keys2.default)(permissions).length === 0) { - delete this.permissionsById[userId]; - } - } - } - }, { - key: '_getAccess', - value: function (accessType, userId) { - if (userId instanceof _ParseUser2.default) { - userId = userId.id; - if (!userId) { - throw new Error('Cannot get access for a ParseUser without an ID'); - } - } else if (userId instanceof _ParseRole2.default) { - var name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - return false; - } - return !!permissions[accessType]; - } - - /** - * Sets whether the given user is allowed to read this object. - * @method setReadAccess - * @param userId An instance of Parse.User or its objectId. - * @param {Boolean} allowed Whether that user should have read access. - */ - - }, { - key: 'setReadAccess', - value: function (userId, allowed) { - this._setAccess('read', userId, allowed); - } - - /** - * Get whether the given user id is *explicitly* allowed to read this object. - * Even if this returns false, the user may still be able to access it if - * getPublicReadAccess returns true or a role that the user belongs to has - * write access. - * @method getReadAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - - }, { - key: 'getReadAccess', - value: function (userId) { - return this._getAccess('read', userId); - } - - /** - * Sets whether the given user id is allowed to write this object. - * @method setWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. - * @param {Boolean} allowed Whether that user should have write access. - */ - - }, { - key: 'setWriteAccess', - value: function (userId, allowed) { - this._setAccess('write', userId, allowed); - } - - /** - * Gets whether the given user id is *explicitly* allowed to write this object. - * Even if this returns false, the user may still be able to write it if - * getPublicWriteAccess returns true or a role that the user belongs to has - * write access. - * @method getWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - - }, { - key: 'getWriteAccess', - value: function (userId) { - return this._getAccess('write', userId); - } - - /** - * Sets whether the public is allowed to read this object. - * @method setPublicReadAccess - * @param {Boolean} allowed - */ - - }, { - key: 'setPublicReadAccess', - value: function (allowed) { - this.setReadAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to read this object. - * @method getPublicReadAccess - * @return {Boolean} - */ - - }, { - key: 'getPublicReadAccess', - value: function () { - return this.getReadAccess(PUBLIC_KEY); - } - - /** - * Sets whether the public is allowed to write this object. - * @method setPublicWriteAccess - * @param {Boolean} allowed - */ - - }, { - key: 'setPublicWriteAccess', - value: function (allowed) { - this.setWriteAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to write this object. - * @method getPublicWriteAccess - * @return {Boolean} - */ - - }, { - key: 'getPublicWriteAccess', - value: function () { - return this.getWriteAccess(PUBLIC_KEY); - } - - /** - * Gets whether users belonging to the given role are allowed - * to read this object. Even if this returns false, the role may - * still be able to write it if a parent role has read access. - * - * @method getRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has read access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'getRoleReadAccess', - value: function (role) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getReadAccess('role:' + role); - } - - /** - * Gets whether users belonging to the given role are allowed - * to write this object. Even if this returns false, the role may - * still be able to write it if a parent role has write access. - * - * @method getRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has write access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'getRoleWriteAccess', - value: function (role) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getWriteAccess('role:' + role); - } - - /** - * Sets whether users belonging to the given role are allowed - * to read this object. - * - * @method setRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can read this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'setRoleReadAccess', - value: function (role, allowed) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setReadAccess('role:' + role, allowed); - } - - /** - * Sets whether users belonging to the given role are allowed - * to write this object. - * - * @method setRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can write this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - - }, { - key: 'setRoleWriteAccess', - value: function (role, allowed) { - if (role instanceof _ParseRole2.default) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setWriteAccess('role:' + role, allowed); - } - }]); - return ParseACL; -}(); - -exports.default = ParseACL; \ No newline at end of file diff --git a/lib/node/ParseConfig.js b/lib/node/ParseConfig.js deleted file mode 100644 index 925e3a864..000000000 --- a/lib/node/ParseConfig.js +++ /dev/null @@ -1,228 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _escape2 = require('./escape'); - -var _escape3 = _interopRequireDefault(_escape2); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Parse.Config is a local representation of configuration data that - * can be set from the Parse dashboard. - * - * @class Parse.Config - * @constructor - */ - -var ParseConfig = function () { - function ParseConfig() { - (0, _classCallCheck3.default)(this, ParseConfig); - - this.attributes = {}; - this._escapedAttributes = {}; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The name of an attribute. - */ - - (0, _createClass3.default)(ParseConfig, [{ - key: 'get', - value: function (attr) { - return this.attributes[attr]; - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The name of an attribute. - */ - - }, { - key: 'escape', - value: function (attr) { - var html = this._escapedAttributes[attr]; - if (html) { - return html; - } - var val = this.attributes[attr]; - var escaped = ''; - if (val != null) { - escaped = (0, _escape3.default)(val.toString()); - } - this._escapedAttributes[attr] = escaped; - return escaped; - } - - /** - * Retrieves the most recently-fetched configuration object, either from - * memory or from local storage if necessary. - * - * @method current - * @static - * @return {Config} The most recently-fetched Parse.Config if it - * exists, else an empty Parse.Config. - */ - - }], [{ - key: 'current', - value: function () { - var controller = _CoreManager2.default.getConfigController(); - return controller.current(); - } - - /** - * Gets a new configuration object from the server. - * @method get - * @static - * @param {Object} options A Backbone-style options object. - * Valid options are:
                            - *
                          • success: Function to call when the get completes successfully. - *
                          • error: Function to call when the get fails. - *
                          - * @return {Parse.Promise} A promise that is resolved with a newly-created - * configuration object when the get completes. - */ - - }, { - key: 'get', - value: function (options) { - options = options || {}; - - var controller = _CoreManager2.default.getConfigController(); - return controller.get()._thenRunCallbacks(options); - } - }]); - return ParseConfig; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseConfig; - -var currentConfig = null; - -var CURRENT_CONFIG_KEY = 'currentConfig'; - -function decodePayload(data) { - try { - var json = JSON.parse(data); - if (json && (typeof json === 'undefined' ? 'undefined' : (0, _typeof3.default)(json)) === 'object') { - return (0, _decode2.default)(json); - } - } catch (e) { - return null; - } -} - -var DefaultController = { - current: function () { - if (currentConfig) { - return currentConfig; - } - - var config = new ParseConfig(); - var storagePath = _Storage2.default.generatePath(CURRENT_CONFIG_KEY); - var configData; - if (!_Storage2.default.async()) { - configData = _Storage2.default.getItem(storagePath); - - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - } - // Return a promise for async storage controllers - return _Storage2.default.getItemAsync(storagePath).then(function (configData) { - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - }); - }, - get: function () { - var RESTController = _CoreManager2.default.getRESTController(); - - return RESTController.request('GET', 'config', {}, {}).then(function (response) { - if (!response || !response.params) { - var error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Config JSON response invalid.'); - return _ParsePromise2.default.error(error); - } - - var config = new ParseConfig(); - config.attributes = {}; - for (var attr in response.params) { - config.attributes[attr] = (0, _decode2.default)(response.params[attr]); - } - currentConfig = config; - return _Storage2.default.setItemAsync(_Storage2.default.generatePath(CURRENT_CONFIG_KEY), (0, _stringify2.default)(response.params)).then(function () { - return config; - }); - }); - } -}; - -_CoreManager2.default.setConfigController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseError.js b/lib/node/ParseError.js deleted file mode 100644 index b3bad4512..000000000 --- a/lib/node/ParseError.js +++ /dev/null @@ -1,507 +0,0 @@ -"use strict"; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = require("babel-runtime/helpers/classCallCheck"); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/** - * Constructs a new Parse.Error object with the given code and message. - * @class Parse.Error - * @constructor - * @param {Number} code An error code constant from Parse.Error. - * @param {String} message A detailed description of the error. - */ -var ParseError = function ParseError(code, message) { - (0, _classCallCheck3.default)(this, ParseError); - - this.code = code; - this.message = message; -}; - -/** - * Error code indicating some error other than those enumerated here. - * @property OTHER_CAUSE - * @static - * @final - */ - -exports.default = ParseError; -ParseError.OTHER_CAUSE = -1; - -/** - * Error code indicating that something has gone wrong with the server. - * If you get this error code, it is Parse's fault. Contact us at - * https://parse.com/help - * @property INTERNAL_SERVER_ERROR - * @static - * @final - */ -ParseError.INTERNAL_SERVER_ERROR = 1; - -/** - * Error code indicating the connection to the Parse servers failed. - * @property CONNECTION_FAILED - * @static - * @final - */ -ParseError.CONNECTION_FAILED = 100; - -/** - * Error code indicating the specified object doesn't exist. - * @property OBJECT_NOT_FOUND - * @static - * @final - */ -ParseError.OBJECT_NOT_FOUND = 101; - -/** - * Error code indicating you tried to query with a datatype that doesn't - * support it, like exact matching an array or object. - * @property INVALID_QUERY - * @static - * @final - */ -ParseError.INVALID_QUERY = 102; - -/** - * Error code indicating a missing or invalid classname. Classnames are - * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the - * only valid characters. - * @property INVALID_CLASS_NAME - * @static - * @final - */ -ParseError.INVALID_CLASS_NAME = 103; - -/** - * Error code indicating an unspecified object id. - * @property MISSING_OBJECT_ID - * @static - * @final - */ -ParseError.MISSING_OBJECT_ID = 104; - -/** - * Error code indicating an invalid key name. Keys are case-sensitive. They - * must start with a letter, and a-zA-Z0-9_ are the only valid characters. - * @property INVALID_KEY_NAME - * @static - * @final - */ -ParseError.INVALID_KEY_NAME = 105; - -/** - * Error code indicating a malformed pointer. You should not see this unless - * you have been mucking about changing internal Parse code. - * @property INVALID_POINTER - * @static - * @final - */ -ParseError.INVALID_POINTER = 106; - -/** - * Error code indicating that badly formed JSON was received upstream. This - * either indicates you have done something unusual with modifying how - * things encode to JSON, or the network is failing badly. - * @property INVALID_JSON - * @static - * @final - */ -ParseError.INVALID_JSON = 107; - -/** - * Error code indicating that the feature you tried to access is only - * available internally for testing purposes. - * @property COMMAND_UNAVAILABLE - * @static - * @final - */ -ParseError.COMMAND_UNAVAILABLE = 108; - -/** - * You must call Parse.initialize before using the Parse library. - * @property NOT_INITIALIZED - * @static - * @final - */ -ParseError.NOT_INITIALIZED = 109; - -/** - * Error code indicating that a field was set to an inconsistent type. - * @property INCORRECT_TYPE - * @static - * @final - */ -ParseError.INCORRECT_TYPE = 111; - -/** - * Error code indicating an invalid channel name. A channel name is either - * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ - * characters and starts with a letter. - * @property INVALID_CHANNEL_NAME - * @static - * @final - */ -ParseError.INVALID_CHANNEL_NAME = 112; - -/** - * Error code indicating that push is misconfigured. - * @property PUSH_MISCONFIGURED - * @static - * @final - */ -ParseError.PUSH_MISCONFIGURED = 115; - -/** - * Error code indicating that the object is too large. - * @property OBJECT_TOO_LARGE - * @static - * @final - */ -ParseError.OBJECT_TOO_LARGE = 116; - -/** - * Error code indicating that the operation isn't allowed for clients. - * @property OPERATION_FORBIDDEN - * @static - * @final - */ -ParseError.OPERATION_FORBIDDEN = 119; - -/** - * Error code indicating the result was not found in the cache. - * @property CACHE_MISS - * @static - * @final - */ -ParseError.CACHE_MISS = 120; - -/** - * Error code indicating that an invalid key was used in a nested - * JSONObject. - * @property INVALID_NESTED_KEY - * @static - * @final - */ -ParseError.INVALID_NESTED_KEY = 121; - -/** - * Error code indicating that an invalid filename was used for ParseFile. - * A valid file name contains only a-zA-Z0-9_. characters and is between 1 - * and 128 characters. - * @property INVALID_FILE_NAME - * @static - * @final - */ -ParseError.INVALID_FILE_NAME = 122; - -/** - * Error code indicating an invalid ACL was provided. - * @property INVALID_ACL - * @static - * @final - */ -ParseError.INVALID_ACL = 123; - -/** - * Error code indicating that the request timed out on the server. Typically - * this indicates that the request is too expensive to run. - * @property TIMEOUT - * @static - * @final - */ -ParseError.TIMEOUT = 124; - -/** - * Error code indicating that the email address was invalid. - * @property INVALID_EMAIL_ADDRESS - * @static - * @final - */ -ParseError.INVALID_EMAIL_ADDRESS = 125; - -/** - * Error code indicating a missing content type. - * @property MISSING_CONTENT_TYPE - * @static - * @final - */ -ParseError.MISSING_CONTENT_TYPE = 126; - -/** - * Error code indicating a missing content length. - * @property MISSING_CONTENT_LENGTH - * @static - * @final - */ -ParseError.MISSING_CONTENT_LENGTH = 127; - -/** - * Error code indicating an invalid content length. - * @property INVALID_CONTENT_LENGTH - * @static - * @final - */ -ParseError.INVALID_CONTENT_LENGTH = 128; - -/** - * Error code indicating a file that was too large. - * @property FILE_TOO_LARGE - * @static - * @final - */ -ParseError.FILE_TOO_LARGE = 129; - -/** - * Error code indicating an error saving a file. - * @property FILE_SAVE_ERROR - * @static - * @final - */ -ParseError.FILE_SAVE_ERROR = 130; - -/** - * Error code indicating that a unique field was given a value that is - * already taken. - * @property DUPLICATE_VALUE - * @static - * @final - */ -ParseError.DUPLICATE_VALUE = 137; - -/** - * Error code indicating that a role's name is invalid. - * @property INVALID_ROLE_NAME - * @static - * @final - */ -ParseError.INVALID_ROLE_NAME = 139; - -/** - * Error code indicating that an application quota was exceeded. Upgrade to - * resolve. - * @property EXCEEDED_QUOTA - * @static - * @final - */ -ParseError.EXCEEDED_QUOTA = 140; - -/** - * Error code indicating that a Cloud Code script failed. - * @property SCRIPT_FAILED - * @static - * @final - */ -ParseError.SCRIPT_FAILED = 141; - -/** - * Error code indicating that a Cloud Code validation failed. - * @property VALIDATION_ERROR - * @static - * @final - */ -ParseError.VALIDATION_ERROR = 142; - -/** - * Error code indicating that invalid image data was provided. - * @property INVALID_IMAGE_DATA - * @static - * @final - */ -ParseError.INVALID_IMAGE_DATA = 143; - -/** - * Error code indicating an unsaved file. - * @property UNSAVED_FILE_ERROR - * @static - * @final - */ -ParseError.UNSAVED_FILE_ERROR = 151; - -/** - * Error code indicating an invalid push time. - * @property INVALID_PUSH_TIME_ERROR - * @static - * @final - */ -ParseError.INVALID_PUSH_TIME_ERROR = 152; - -/** - * Error code indicating an error deleting a file. - * @property FILE_DELETE_ERROR - * @static - * @final - */ -ParseError.FILE_DELETE_ERROR = 153; - -/** - * Error code indicating that the application has exceeded its request - * limit. - * @property REQUEST_LIMIT_EXCEEDED - * @static - * @final - */ -ParseError.REQUEST_LIMIT_EXCEEDED = 155; - -/** - * Error code indicating an invalid event name. - * @property INVALID_EVENT_NAME - * @static - * @final - */ -ParseError.INVALID_EVENT_NAME = 160; - -/** - * Error code indicating that the username is missing or empty. - * @property USERNAME_MISSING - * @static - * @final - */ -ParseError.USERNAME_MISSING = 200; - -/** - * Error code indicating that the password is missing or empty. - * @property PASSWORD_MISSING - * @static - * @final - */ -ParseError.PASSWORD_MISSING = 201; - -/** - * Error code indicating that the username has already been taken. - * @property USERNAME_TAKEN - * @static - * @final - */ -ParseError.USERNAME_TAKEN = 202; - -/** - * Error code indicating that the email has already been taken. - * @property EMAIL_TAKEN - * @static - * @final - */ -ParseError.EMAIL_TAKEN = 203; - -/** - * Error code indicating that the email is missing, but must be specified. - * @property EMAIL_MISSING - * @static - * @final - */ -ParseError.EMAIL_MISSING = 204; - -/** - * Error code indicating that a user with the specified email was not found. - * @property EMAIL_NOT_FOUND - * @static - * @final - */ -ParseError.EMAIL_NOT_FOUND = 205; - -/** - * Error code indicating that a user object without a valid session could - * not be altered. - * @property SESSION_MISSING - * @static - * @final - */ -ParseError.SESSION_MISSING = 206; - -/** - * Error code indicating that a user can only be created through signup. - * @property MUST_CREATE_USER_THROUGH_SIGNUP - * @static - * @final - */ -ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; - -/** - * Error code indicating that an an account being linked is already linked - * to another user. - * @property ACCOUNT_ALREADY_LINKED - * @static - * @final - */ -ParseError.ACCOUNT_ALREADY_LINKED = 208; - -/** - * Error code indicating that the current session token is invalid. - * @property INVALID_SESSION_TOKEN - * @static - * @final - */ -ParseError.INVALID_SESSION_TOKEN = 209; - -/** - * Error code indicating that a user cannot be linked to an account because - * that account's id could not be found. - * @property LINKED_ID_MISSING - * @static - * @final - */ -ParseError.LINKED_ID_MISSING = 250; - -/** - * Error code indicating that a user with a linked (e.g. Facebook) account - * has an invalid session. - * @property INVALID_LINKED_SESSION - * @static - * @final - */ -ParseError.INVALID_LINKED_SESSION = 251; - -/** - * Error code indicating that a service being linked (e.g. Facebook or - * Twitter) is unsupported. - * @property UNSUPPORTED_SERVICE - * @static - * @final - */ -ParseError.UNSUPPORTED_SERVICE = 252; - -/** - * Error code indicating that there were multiple errors. Aggregate errors - * have an "errors" property, which is an array of error objects with more - * detail about each error that occurred. - * @property AGGREGATE_ERROR - * @static - * @final - */ -ParseError.AGGREGATE_ERROR = 600; - -/** - * Error code indicating the client was unable to read an input file. - * @property FILE_READ_ERROR - * @static - * @final - */ -ParseError.FILE_READ_ERROR = 601; - -/** - * Error code indicating a real error code is unavailable because - * we had to use an XDomainRequest object to allow CORS requests in - * Internet Explorer, which strips the body from HTTP responses that have - * a non-2XX status code. - * @property X_DOMAIN_REQUEST - * @static - * @final - */ -ParseError.X_DOMAIN_REQUEST = 602; \ No newline at end of file diff --git a/lib/node/ParseFile.js b/lib/node/ParseFile.js deleted file mode 100644 index 48efdb9d8..000000000 --- a/lib/node/ParseFile.js +++ /dev/null @@ -1,291 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; - -function b64Digit(number) { - if (number < 26) { - return String.fromCharCode(65 + number); - } - if (number < 52) { - return String.fromCharCode(97 + (number - 26)); - } - if (number < 62) { - return String.fromCharCode(48 + (number - 52)); - } - if (number === 62) { - return '+'; - } - if (number === 63) { - return '/'; - } - throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); -} - -/** - * A Parse.File is a local representation of a file that is saved to the Parse - * cloud. - * @class Parse.File - * @constructor - * @param name {String} The file's name. This will be prefixed by a unique - * value once the file has finished saving. The file name must begin with - * an alphanumeric character, and consist of alphanumeric characters, - * periods, spaces, underscores, or dashes. - * @param data {Array} The data for the file, as either: - * 1. an Array of byte value Numbers, or - * 2. an Object like { base64: "..." } with a base64-encoded String. - * 3. a File object selected with a file upload control. (3) only works - * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. - * For example:
                          - * var fileUploadControl = $("#profilePhotoFileUpload")[0];
                          - * if (fileUploadControl.files.length > 0) {
                          - *   var file = fileUploadControl.files[0];
                          - *   var name = "photo.jpg";
                          - *   var parseFile = new Parse.File(name, file);
                          - *   parseFile.save().then(function() {
                          - *     // The file has been saved to Parse.
                          - *   }, function(error) {
                          - *     // The file either could not be read, or could not be saved to Parse.
                          - *   });
                          - * }
                          - * @param type {String} Optional Content-Type header to use for the file. If - * this is omitted, the content type will be inferred from the name's - * extension. - */ - -var ParseFile = function () { - function ParseFile(name, data, type) { - (0, _classCallCheck3.default)(this, ParseFile); - - var specifiedType = type || ''; - - this._name = name; - - if (data !== undefined) { - if (Array.isArray(data)) { - this._source = { - format: 'base64', - base64: ParseFile.encodeBase64(data), - type: specifiedType - }; - } else if (typeof File !== 'undefined' && data instanceof File) { - this._source = { - format: 'file', - file: data, - type: specifiedType - }; - } else if (data && typeof data.base64 === 'string') { - var _base = data.base64; - var commaIndex = _base.indexOf(','); - - if (commaIndex !== -1) { - var matches = dataUriRegexp.exec(_base.slice(0, commaIndex + 1)); - // if data URI with type and charset, there will be 4 matches. - this._source = { - format: 'base64', - base64: _base.slice(commaIndex + 1), - type: matches[1] - }; - } else { - this._source = { - format: 'base64', - base64: _base, - type: specifiedType - }; - } - } else { - throw new TypeError('Cannot create a Parse.File with that data.'); - } - } - } - - /** - * Gets the name of the file. Before save is called, this is the filename - * given by the user. After save is called, that name gets prefixed with a - * unique identifier. - * @method name - * @return {String} - */ - - (0, _createClass3.default)(ParseFile, [{ - key: 'name', - value: function () { - return this._name; - } - - /** - * Gets the url of the file. It is only available after you save the file or - * after you get the file from a Parse.Object. - * @method url - * @param {Object} options An object to specify url options - * @return {String} - */ - - }, { - key: 'url', - value: function (options) { - options = options || {}; - if (!this._url) { - return; - } - if (options.forceSecure) { - return this._url.replace(/^http:\/\//i, 'https://'); - } else { - return this._url; - } - } - - /** - * Saves the file to the Parse cloud. - * @method save - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} Promise that is resolved when the save finishes. - */ - - }, { - key: 'save', - value: function (options) { - var _this = this; - - options = options || {}; - var controller = _CoreManager2.default.getFileController(); - if (!this._previousSave) { - if (this._source.format === 'file') { - this._previousSave = controller.saveFile(this._name, this._source).then(function (res) { - _this._name = res.name; - _this._url = res.url; - return _this; - }); - } else { - this._previousSave = controller.saveBase64(this._name, this._source).then(function (res) { - _this._name = res.name; - _this._url = res.url; - return _this; - }); - } - } - if (this._previousSave) { - return this._previousSave._thenRunCallbacks(options); - } - } - }, { - key: 'toJSON', - value: function () { - return { - __type: 'File', - name: this._name, - url: this._url - }; - } - }, { - key: 'equals', - value: function (other) { - if (this === other) { - return true; - } - // Unsaved Files are never equal, since they will be saved to different URLs - return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; - } - }], [{ - key: 'fromJSON', - value: function (obj) { - if (obj.__type !== 'File') { - throw new TypeError('JSON object does not represent a ParseFile'); - } - var file = new ParseFile(obj.name); - file._url = obj.url; - return file; - } - }, { - key: 'encodeBase64', - value: function (bytes) { - var chunks = []; - chunks.length = Math.ceil(bytes.length / 3); - for (var i = 0; i < chunks.length; i++) { - var b1 = bytes[i * 3]; - var b2 = bytes[i * 3 + 1] || 0; - var b3 = bytes[i * 3 + 2] || 0; - - var has2 = i * 3 + 1 < bytes.length; - var has3 = i * 3 + 2 < bytes.length; - - chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); - } - - return chunks.join(''); - } - }]); - return ParseFile; -}(); - -exports.default = ParseFile; - -var DefaultController = { - saveFile: function (name, source) { - if (source.format !== 'file') { - throw new Error('saveFile can only be used with File-type sources.'); - } - // To directly upload a File, we use a REST-style AJAX request - var headers = { - 'X-Parse-Application-ID': _CoreManager2.default.get('APPLICATION_ID'), - 'X-Parse-JavaScript-Key': _CoreManager2.default.get('JAVASCRIPT_KEY'), - 'Content-Type': source.type || (source.file ? source.file.type : null) - }; - var url = _CoreManager2.default.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += 'files/' + name; - return _CoreManager2.default.getRESTController().ajax('POST', url, source.file, headers); - }, - - saveBase64: function (name, source) { - if (source.format !== 'base64') { - throw new Error('saveBase64 can only be used with Base64-type sources.'); - } - var data = { - base64: source.base64 - }; - if (source.type) { - data._ContentType = source.type; - } - - return _CoreManager2.default.getRESTController().request('POST', 'files/' + name, data); - } -}; - -_CoreManager2.default.setFileController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseGeoPoint.js b/lib/node/ParseGeoPoint.js deleted file mode 100644 index 98691f85b..000000000 --- a/lib/node/ParseGeoPoint.js +++ /dev/null @@ -1,235 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new GeoPoint with any of the following forms:
                          - *
                          - *   new GeoPoint(otherGeoPoint)
                          - *   new GeoPoint(30, 30)
                          - *   new GeoPoint([30, 30])
                          - *   new GeoPoint({latitude: 30, longitude: 30})
                          - *   new GeoPoint()  // defaults to (0, 0)
                          - *   
                          - * @class Parse.GeoPoint - * @constructor - * - *

                          Represents a latitude / longitude point that may be associated - * with a key in a ParseObject or used as a reference point for geo queries. - * This allows proximity-based queries on the key.

                          - * - *

                          Only one key in a class may contain a GeoPoint.

                          - * - *

                          Example:

                          - *   var point = new Parse.GeoPoint(30.0, -20.0);
                          - *   var object = new Parse.Object("PlaceObject");
                          - *   object.set("location", point);
                          - *   object.save();

                          - */ -var ParseGeoPoint = function () { - function ParseGeoPoint(arg1, arg2) { - (0, _classCallCheck3.default)(this, ParseGeoPoint); - - if (Array.isArray(arg1)) { - ParseGeoPoint._validate(arg1[0], arg1[1]); - this._latitude = arg1[0]; - this._longitude = arg1[1]; - } else if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object') { - ParseGeoPoint._validate(arg1.latitude, arg1.longitude); - this._latitude = arg1.latitude; - this._longitude = arg1.longitude; - } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { - ParseGeoPoint._validate(arg1, arg2); - this._latitude = arg1; - this._longitude = arg2; - } else { - this._latitude = 0; - this._longitude = 0; - } - } - - /** - * North-south portion of the coordinate, in range [-90, 90]. - * Throws an exception if set out of range in a modern browser. - * @property latitude - * @type Number - */ - - (0, _createClass3.default)(ParseGeoPoint, [{ - key: 'toJSON', - - /** - * Returns a JSON representation of the GeoPoint, suitable for Parse. - * @method toJSON - * @return {Object} - */ - value: function () { - ParseGeoPoint._validate(this._latitude, this._longitude); - return { - __type: 'GeoPoint', - latitude: this._latitude, - longitude: this._longitude - }; - } - }, { - key: 'equals', - value: function (other) { - return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; - } - - /** - * Returns the distance from this GeoPoint to another in radians. - * @method radiansTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'radiansTo', - value: function (point) { - var d2r = Math.PI / 180.0; - var lat1rad = this.latitude * d2r; - var long1rad = this.longitude * d2r; - var lat2rad = point.latitude * d2r; - var long2rad = point.longitude * d2r; - - var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); - var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); - // Square of half the straight line chord distance between both points. - var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; - a = Math.min(1.0, a); - return 2 * Math.asin(Math.sqrt(a)); - } - - /** - * Returns the distance from this GeoPoint to another in kilometers. - * @method kilometersTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'kilometersTo', - value: function (point) { - return this.radiansTo(point) * 6371.0; - } - - /** - * Returns the distance from this GeoPoint to another in miles. - * @method milesTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - - }, { - key: 'milesTo', - value: function (point) { - return this.radiansTo(point) * 3958.8; - } - - /** - * Throws an exception if the given lat-long is out of bounds. - */ - - }, { - key: 'latitude', - get: function () { - return this._latitude; - }, - set: function (val) { - ParseGeoPoint._validate(val, this.longitude); - this._latitude = val; - } - - /** - * East-west portion of the coordinate, in range [-180, 180]. - * Throws if set out of range in a modern browser. - * @property longitude - * @type Number - */ - - }, { - key: 'longitude', - get: function () { - return this._longitude; - }, - set: function (val) { - ParseGeoPoint._validate(this.latitude, val); - this._longitude = val; - } - }], [{ - key: '_validate', - value: function (latitude, longitude) { - if (latitude !== latitude || longitude !== longitude) { - throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); - } - if (latitude < -90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); - } - if (latitude > 90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); - } - if (longitude < -180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); - } - if (longitude > 180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); - } - } - - /** - * Creates a GeoPoint with the user's current location, if available. - * Calls options.success with a new GeoPoint instance or calls options.error. - * @method current - * @param {Object} options An object with success and error callbacks. - * @static - */ - - }, { - key: 'current', - value: function (options) { - var promise = new _ParsePromise2.default(); - navigator.geolocation.getCurrentPosition(function (location) { - promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); - }, function (error) { - promise.reject(error); - }); - - return promise._thenRunCallbacks(options); - } - }]); - return ParseGeoPoint; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseGeoPoint; \ No newline at end of file diff --git a/lib/node/ParseHooks.js b/lib/node/ParseHooks.js deleted file mode 100644 index a2057e899..000000000 --- a/lib/node/ParseHooks.js +++ /dev/null @@ -1,162 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _promise = require('babel-runtime/core-js/promise'); - -var _promise2 = _interopRequireDefault(_promise); - -exports.getFunctions = getFunctions; -exports.getTriggers = getTriggers; -exports.getFunction = getFunction; -exports.getTrigger = getTrigger; -exports.createFunction = createFunction; -exports.createTrigger = createTrigger; -exports.create = create; -exports.updateFunction = updateFunction; -exports.updateTrigger = updateTrigger; -exports.update = update; -exports.removeFunction = removeFunction; -exports.removeTrigger = removeTrigger; -exports.remove = remove; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function getFunctions() { - return _CoreManager2.default.getHooksController().get("functions"); -} - -function getTriggers() { - return _CoreManager2.default.getHooksController().get("triggers"); -} - -function getFunction(name) { - return _CoreManager2.default.getHooksController().get("functions", name); -} - -function getTrigger(className, triggerName) { - return _CoreManager2.default.getHooksController().get("triggers", className, triggerName); -} - -function createFunction(functionName, url) { - return create({ functionName: functionName, url: url }); -} - -function createTrigger(className, triggerName, url) { - return create({ className: className, triggerName: triggerName, url: url }); -} - -function create(hook) { - return _CoreManager2.default.getHooksController().create(hook); -} - -function updateFunction(functionName, url) { - return update({ functionName: functionName, url: url }); -} - -function updateTrigger(className, triggerName, url) { - return update({ className: className, triggerName: triggerName, url: url }); -} - -function update(hook) { - return _CoreManager2.default.getHooksController().update(hook); -} - -function removeFunction(functionName) { - return remove({ functionName: functionName }); -} - -function removeTrigger(className, triggerName) { - return remove({ className: className, triggerName: triggerName }); -} - -function remove(hook) { - return _CoreManager2.default.getHooksController().remove(hook); -} - -var DefaultController = { - get: function (type, functionName, triggerName) { - var url = "/hooks/" + type; - if (functionName) { - url += "/" + functionName; - if (triggerName) { - url += "/" + triggerName; - } - } - return this.sendRequest("GET", url); - }, - create: function (hook) { - var url; - if (hook.functionName && hook.url) { - url = "/hooks/functions"; - } else if (hook.className && hook.triggerName && hook.url) { - url = "/hooks/triggers"; - } else { - return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest("POST", url, hook); - }, - remove: function (hook) { - var url; - if (hook.functionName) { - url = "/hooks/functions/" + hook.functionName; - delete hook.functionName; - } else if (hook.className && hook.triggerName) { - url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; - delete hook.className; - delete hook.triggerName; - } else { - return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest("PUT", url, { "__op": "Delete" }); - }, - update: function (hook) { - var url; - if (hook.functionName && hook.url) { - url = "/hooks/functions/" + hook.functionName; - delete hook.functionName; - } else if (hook.className && hook.triggerName && hook.url) { - url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; - delete hook.className; - delete hook.triggerName; - } else { - return _promise2.default.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest('PUT', url, hook); - }, - sendRequest: function (method, url, body) { - return _CoreManager2.default.getRESTController().request(method, url, body, { useMasterKey: true }).then(function (res) { - var decoded = (0, _decode2.default)(res); - if (decoded) { - return _ParsePromise2.default.as(decoded); - } - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'The server returned an invalid response.')); - }); - } -}; - -_CoreManager2.default.setHooksController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseInstallation.js b/lib/node/ParseInstallation.js deleted file mode 100644 index 02d7be1d8..000000000 --- a/lib/node/ParseInstallation.js +++ /dev/null @@ -1,65 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var Installation = function (_ParseObject) { - (0, _inherits3.default)(Installation, _ParseObject); - - function Installation(attributes) { - (0, _classCallCheck3.default)(this, Installation); - - var _this = (0, _possibleConstructorReturn3.default)(this, (Installation.__proto__ || (0, _getPrototypeOf2.default)(Installation)).call(this, '_Installation')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - return _this; - } - - return Installation; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = Installation; - -_ParseObject3.default.registerSubclass('_Installation', Installation); \ No newline at end of file diff --git a/lib/node/ParseLiveQuery.js b/lib/node/ParseLiveQuery.js deleted file mode 100644 index a3e5fe31d..000000000 --- a/lib/node/ParseLiveQuery.js +++ /dev/null @@ -1,241 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _EventEmitter = require('./EventEmitter'); - -var _EventEmitter2 = _interopRequireDefault(_EventEmitter); - -var _LiveQueryClient = require('./LiveQueryClient'); - -var _LiveQueryClient2 = _interopRequireDefault(_LiveQueryClient); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function open() { - var LiveQueryController = _CoreManager2.default.getLiveQueryController(); - LiveQueryController.open(); -} - -function close() { - var LiveQueryController = _CoreManager2.default.getLiveQueryController(); - LiveQueryController.close(); -} - -/** - * - * We expose three events to help you monitor the status of the WebSocket connection: - * - *

                          Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                          - * Parse.LiveQuery.on('open', () => {
                          - * 
                          - * });

                          - * - *

                          Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                          - * Parse.LiveQuery.on('close', () => {
                          - * 
                          - * });

                          - * - *

                          Error - When some network error or LiveQuery server error happens, you'll get this event. - * - *

                          - * Parse.LiveQuery.on('error', (error) => {
                          - * 
                          - * });

                          - * - * @class Parse.LiveQuery - * @static - * - */ -var LiveQuery = new _EventEmitter2.default(); - -/** - * After open is called, the LiveQuery will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ -LiveQuery.open = open; - -/** - * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). - * This function will close the WebSocket connection to the LiveQuery server, - * cancel the auto reconnect, and unsubscribe all subscriptions based on it. - * If you call query.subscribe() after this, we'll create a new WebSocket - * connection to the LiveQuery server. - * - * @method close - */ - -LiveQuery.close = close; -// Register a default onError callback to make sure we do not crash on error -LiveQuery.on('error', function () {}); - -exports.default = LiveQuery; - -function getSessionToken() { - var controller = _CoreManager2.default.getUserController(); - return controller.currentUserAsync().then(function (currentUser) { - return currentUser ? currentUser.getSessionToken() : undefined; - }); -} - -function getLiveQueryClient() { - return _CoreManager2.default.getLiveQueryController().getDefaultLiveQueryClient(); -} - -var defaultLiveQueryClient = void 0; -var DefaultLiveQueryController = { - setDefaultLiveQueryClient: function (liveQueryClient) { - defaultLiveQueryClient = liveQueryClient; - }, - getDefaultLiveQueryClient: function () { - if (defaultLiveQueryClient) { - return _ParsePromise2.default.as(defaultLiveQueryClient); - } - - return getSessionToken().then(function (sessionToken) { - var liveQueryServerURL = _CoreManager2.default.get('LIVEQUERY_SERVER_URL'); - - if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL - if (!liveQueryServerURL) { - var tempServerURL = _CoreManager2.default.get('SERVER_URL'); - var protocol = 'ws://'; - // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix - if (tempServerURL.indexOf('https') === 0) { - protocol = 'wss://'; - } - var host = tempServerURL.replace(/^https?:\/\//, ''); - liveQueryServerURL = protocol + host; - _CoreManager2.default.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); - } - - var applicationId = _CoreManager2.default.get('APPLICATION_ID'); - var javascriptKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); - var masterKey = _CoreManager2.default.get('MASTER_KEY'); - // Get currentUser sessionToken if possible - defaultLiveQueryClient = new _LiveQueryClient2.default({ - applicationId: applicationId, - serverURL: liveQueryServerURL, - javascriptKey: javascriptKey, - masterKey: masterKey, - sessionToken: sessionToken - }); - // Register a default onError callback to make sure we do not crash on error - // Cannot create these events on a nested way because of EventEmiiter from React Native - defaultLiveQueryClient.on('error', function (error) { - LiveQuery.emit('error', error); - }); - defaultLiveQueryClient.on('open', function () { - LiveQuery.emit('open'); - }); - defaultLiveQueryClient.on('close', function () { - LiveQuery.emit('close'); - }); - - return defaultLiveQueryClient; - }); - }, - open: function () { - var _this = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this.resolve(liveQueryClient.open()); - }); - }, - close: function () { - var _this2 = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this2.resolve(liveQueryClient.close()); - }); - }, - subscribe: function (query) { - var _this3 = this; - - var subscriptionWrap = new _EventEmitter2.default(); - - getLiveQueryClient().then(function (liveQueryClient) { - if (liveQueryClient.shouldOpen()) { - liveQueryClient.open(); - } - var promiseSessionToken = getSessionToken(); - // new event emitter - return promiseSessionToken.then(function (sessionToken) { - - var subscription = liveQueryClient.subscribe(query, sessionToken); - // enter, leave create, etc - - subscriptionWrap.id = subscription.id; - subscriptionWrap.query = subscription.query; - subscriptionWrap.sessionToken = subscription.sessionToken; - subscriptionWrap.unsubscribe = subscription.unsubscribe; - // Cannot create these events on a nested way because of EventEmiiter from React Native - subscription.on('open', function () { - subscriptionWrap.emit('open'); - }); - subscription.on('create', function (object) { - subscriptionWrap.emit('create', object); - }); - subscription.on('update', function (object) { - subscriptionWrap.emit('update', object); - }); - subscription.on('enter', function (object) { - subscriptionWrap.emit('enter', object); - }); - subscription.on('leave', function (object) { - subscriptionWrap.emit('leave', object); - }); - subscription.on('delete', function (object) { - subscriptionWrap.emit('delete', object); - }); - - _this3.resolve(); - }); - }); - return subscriptionWrap; - }, - unsubscribe: function (subscription) { - var _this4 = this; - - getLiveQueryClient().then(function (liveQueryClient) { - _this4.resolve(liveQueryClient.unsubscribe(subscription)); - }); - }, - _clearCachedDefaultClient: function () { - defaultLiveQueryClient = null; - } -}; - -_CoreManager2.default.setLiveQueryController(DefaultLiveQueryController); \ No newline at end of file diff --git a/lib/node/ParseObject.js b/lib/node/ParseObject.js deleted file mode 100644 index f08795e52..000000000 --- a/lib/node/ParseObject.js +++ /dev/null @@ -1,2001 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _defineProperty = require('babel-runtime/core-js/object/define-property'); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -var _create = require('babel-runtime/core-js/object/create'); - -var _create2 = _interopRequireDefault(_create); - -var _freeze = require('babel-runtime/core-js/object/freeze'); - -var _freeze2 = _interopRequireDefault(_freeze); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _canBeSerialized = require('./canBeSerialized'); - -var _canBeSerialized2 = _interopRequireDefault(_canBeSerialized); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _equals = require('./equals'); - -var _equals2 = _interopRequireDefault(_equals); - -var _escape2 = require('./escape'); - -var _escape3 = _interopRequireDefault(_escape2); - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _parseDate = require('./parseDate'); - -var _parseDate2 = _interopRequireDefault(_parseDate); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseOp = require('./ParseOp'); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseQuery = require('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _SingleInstanceStateController = require('./SingleInstanceStateController'); - -var SingleInstanceStateController = _interopRequireWildcard(_SingleInstanceStateController); - -var _unique = require('./unique'); - -var _unique2 = _interopRequireDefault(_unique); - -var _UniqueInstanceStateController = require('./UniqueInstanceStateController'); - -var UniqueInstanceStateController = _interopRequireWildcard(_UniqueInstanceStateController); - -var _unsavedChildren = require('./unsavedChildren'); - -var _unsavedChildren2 = _interopRequireDefault(_unsavedChildren); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -// Mapping of class names to constructors, so we can populate objects from the -// server with appropriate subclasses of ParseObject -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var classMap = {}; - -// Global counter for generating unique local Ids -var localCount = 0; -// Global counter for generating unique Ids for non-single-instance objects -var objectCount = 0; -// On web clients, objects are single-instance: any two objects with the same Id -// will have the same attributes. However, this may be dangerous default -// behavior in a server scenario -var singleInstance = !_CoreManager2.default.get('IS_NODE'); -if (singleInstance) { - _CoreManager2.default.setObjectStateController(SingleInstanceStateController); -} else { - _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); -} - -function getServerUrlPath() { - var serverUrl = _CoreManager2.default.get('SERVER_URL'); - if (serverUrl[serverUrl.length - 1] !== '/') { - serverUrl += '/'; - } - var url = serverUrl.replace(/https?:\/\//, ''); - return url.substr(url.indexOf('/')); -} - -/** - * Creates a new model with defined attributes. - * - *

                          You won't normally call this method directly. It is recommended that - * you use a subclass of Parse.Object instead, created by calling - * extend.

                          - * - *

                          However, if you don't want to use a subclass, or aren't sure which - * subclass is appropriate, you can use this form:

                          - *     var object = new Parse.Object("ClassName");
                          - * 
                          - * That is basically equivalent to:
                          - *     var MyClass = Parse.Object.extend("ClassName");
                          - *     var object = new MyClass();
                          - * 

                          - * - * @class Parse.Object - * @constructor - * @param {String} className The class name for the object - * @param {Object} attributes The initial set of data to store in the object. - * @param {Object} options The options for this object instance. - */ - -var ParseObject = function () { - /** - * The ID of this object, unique within its class. - * @property id - * @type String - */ - function ParseObject(className, attributes, options) { - (0, _classCallCheck3.default)(this, ParseObject); - - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - var toSet = null; - this._objCount = objectCount++; - if (typeof className === 'string') { - this.className = className; - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - toSet = attributes; - } - } else if (className && (typeof className === 'undefined' ? 'undefined' : (0, _typeof3.default)(className)) === 'object') { - this.className = className.className; - toSet = {}; - for (var attr in className) { - if (attr !== 'className') { - toSet[attr] = className[attr]; - } - } - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - options = attributes; - } - } - if (toSet && !this.set(toSet, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - - /** Prototype getters / setters **/ - - (0, _createClass3.default)(ParseObject, [{ - key: '_getId', - - /** Private methods **/ - - /** - * Returns a local or server Id used uniquely identify this object - */ - value: function () { - if (typeof this.id === 'string') { - return this.id; - } - if (typeof this._localId === 'string') { - return this._localId; - } - var localId = 'local' + String(localCount++); - this._localId = localId; - return localId; - } - - /** - * Returns a unique identifier used to pull data from the State Controller. - */ - - }, { - key: '_getStateIdentifier', - value: function () { - if (singleInstance) { - var _id = this.id; - if (!_id) { - _id = this._getId(); - } - return { - id: _id, - className: this.className - }; - } else { - return this; - } - } - }, { - key: '_getServerData', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return stateController.getServerData(this._getStateIdentifier()); - } - }, { - key: '_clearServerData', - value: function () { - var serverData = this._getServerData(); - var unset = {}; - for (var attr in serverData) { - unset[attr] = undefined; - } - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.setServerData(this._getStateIdentifier(), unset); - } - }, { - key: '_getPendingOps', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return stateController.getPendingOps(this._getStateIdentifier()); - } - }, { - key: '_clearPendingOps', - value: function () { - var pending = this._getPendingOps(); - var latest = pending[pending.length - 1]; - var keys = (0, _keys2.default)(latest); - keys.forEach(function (key) { - delete latest[key]; - }); - } - }, { - key: '_getDirtyObjectAttributes', - value: function () { - var attributes = this.attributes; - var stateController = _CoreManager2.default.getObjectStateController(); - var objectCache = stateController.getObjectCache(this._getStateIdentifier()); - var dirty = {}; - for (var attr in attributes) { - var val = attributes[attr]; - if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object' && !(val instanceof ParseObject) && !(val instanceof _ParseFile2.default) && !(val instanceof _ParseRelation2.default)) { - // Due to the way browsers construct maps, the key order will not change - // unless the object is changed - try { - var json = (0, _encode2.default)(val, false, true); - var stringified = (0, _stringify2.default)(json); - if (objectCache[attr] !== stringified) { - dirty[attr] = val; - } - } catch (e) { - // Error occurred, possibly by a nested unsaved pointer in a mutable container - // No matter how it happened, it indicates a change in the attribute - dirty[attr] = val; - } - } - } - return dirty; - } - }, { - key: '_toFullJSON', - value: function (seen) { - var json = this.toJSON(seen); - json.__type = 'Object'; - json.className = this.className; - return json; - } - }, { - key: '_getSaveJSON', - value: function () { - var pending = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - var json = {}; - - for (var attr in dirtyObjects) { - json[attr] = new _ParseOp.SetOp(dirtyObjects[attr]).toJSON(); - } - for (attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - return json; - } - }, { - key: '_getSaveParams', - value: function () { - var method = this.id ? 'PUT' : 'POST'; - var body = this._getSaveJSON(); - var path = 'classes/' + this.className; - if (this.id) { - path += '/' + this.id; - } else if (this.className === '_User') { - path = 'users'; - } - return { - method: method, - body: body, - path: path - }; - } - }, { - key: '_finishFetch', - value: function (serverData) { - if (!this.id && serverData.objectId) { - this.id = serverData.objectId; - } - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.initializeState(this._getStateIdentifier()); - var decoded = {}; - for (var attr in serverData) { - if (attr === 'ACL') { - decoded[attr] = new _ParseACL2.default(serverData[attr]); - } else if (attr !== 'objectId') { - decoded[attr] = (0, _decode2.default)(serverData[attr]); - if (decoded[attr] instanceof _ParseRelation2.default) { - decoded[attr]._ensureParentAndKey(this, attr); - } - } - } - if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = (0, _parseDate2.default)(decoded.createdAt); - } - if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = (0, _parseDate2.default)(decoded.updatedAt); - } - if (!decoded.updatedAt && decoded.createdAt) { - decoded.updatedAt = decoded.createdAt; - } - stateController.commitServerChanges(this._getStateIdentifier(), decoded); - } - }, { - key: '_setExisted', - value: function (existed) { - var stateController = _CoreManager2.default.getObjectStateController(); - var state = stateController.getState(this._getStateIdentifier()); - if (state) { - state.existed = existed; - } - } - }, { - key: '_migrateId', - value: function (serverId) { - if (this._localId && serverId) { - if (singleInstance) { - var stateController = _CoreManager2.default.getObjectStateController(); - var oldState = stateController.removeState(this._getStateIdentifier()); - this.id = serverId; - delete this._localId; - if (oldState) { - stateController.initializeState(this._getStateIdentifier(), oldState); - } - } else { - this.id = serverId; - delete this._localId; - } - } - } - }, { - key: '_handleSaveResponse', - value: function (response, status) { - var changes = {}; - - var stateController = _CoreManager2.default.getObjectStateController(); - var pending = stateController.popPendingState(this._getStateIdentifier()); - for (var attr in pending) { - if (pending[attr] instanceof _ParseOp.RelationOp) { - changes[attr] = pending[attr].applyTo(undefined, this, attr); - } else if (!(attr in response)) { - // Only SetOps and UnsetOps should not come back with results - changes[attr] = pending[attr].applyTo(undefined); - } - } - for (attr in response) { - if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { - changes[attr] = (0, _parseDate2.default)(response[attr]); - } else if (attr === 'ACL') { - changes[attr] = new _ParseACL2.default(response[attr]); - } else if (attr !== 'objectId') { - changes[attr] = (0, _decode2.default)(response[attr]); - if (changes[attr] instanceof _ParseOp.UnsetOp) { - changes[attr] = undefined; - } - } - } - if (changes.createdAt && !changes.updatedAt) { - changes.updatedAt = changes.createdAt; - } - - this._migrateId(response.objectId); - - if (status !== 201) { - this._setExisted(true); - } - - stateController.commitServerChanges(this._getStateIdentifier(), changes); - } - }, { - key: '_handleSaveError', - value: function () { - this._getPendingOps(); - - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.mergeFirstPendingState(this._getStateIdentifier()); - } - - /** Public methods **/ - - }, { - key: 'initialize', - value: function () {} - // NOOP - - - /** - * Returns a JSON version of the object suitable for saving to Parse. - * @method toJSON - * @return {Object} - */ - - }, { - key: 'toJSON', - value: function (seen) { - var seenEntry = this.id ? this.className + ':' + this.id : this; - var seen = seen || [seenEntry]; - var json = {}; - var attrs = this.attributes; - for (var attr in attrs) { - if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { - json[attr] = attrs[attr].toJSON(); - } else { - json[attr] = (0, _encode2.default)(attrs[attr], false, false, seen); - } - } - var pending = this._getPendingOps(); - for (var attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - - if (this.id) { - json.objectId = this.id; - } - return json; - } - - /** - * Determines whether this ParseObject is equal to another ParseObject - * @method equals - * @return {Boolean} - */ - - }, { - key: 'equals', - value: function (other) { - if (this === other) { - return true; - } - return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; - } - - /** - * Returns true if this object has been modified since its last - * save/refresh. If an attribute is specified, it returns true only if that - * particular attribute has been modified since the last save/refresh. - * @method dirty - * @param {String} attr An attribute name (optional). - * @return {Boolean} - */ - - }, { - key: 'dirty', - value: function (attr) { - if (!this.id) { - return true; - } - var pendingOps = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - if (attr) { - if (dirtyObjects.hasOwnProperty(attr)) { - return true; - } - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i].hasOwnProperty(attr)) { - return true; - } - } - return false; - } - if ((0, _keys2.default)(pendingOps[0]).length !== 0) { - return true; - } - if ((0, _keys2.default)(dirtyObjects).length !== 0) { - return true; - } - return false; - } - - /** - * Returns an array of keys that have been modified since last save/refresh - * @method dirtyKeys - * @return {Array of string} - */ - - }, { - key: 'dirtyKeys', - value: function () { - var pendingOps = this._getPendingOps(); - var keys = {}; - for (var i = 0; i < pendingOps.length; i++) { - for (var attr in pendingOps[i]) { - keys[attr] = true; - } - } - var dirtyObjects = this._getDirtyObjectAttributes(); - for (var attr in dirtyObjects) { - keys[attr] = true; - } - return (0, _keys2.default)(keys); - } - - /** - * Gets a Pointer referencing this Object. - * @method toPointer - * @return {Object} - */ - - }, { - key: 'toPointer', - value: function () { - if (!this.id) { - throw new Error('Cannot create a pointer to an unsaved ParseObject'); - } - return { - __type: 'Pointer', - className: this.className, - objectId: this.id - }; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'get', - value: function (attr) { - return this.attributes[attr]; - } - - /** - * Gets a relation on the given class for the attribute. - * @method relation - * @param String attr The attribute to get the relation for. - */ - - }, { - key: 'relation', - value: function (attr) { - var value = this.get(attr); - if (value) { - if (!(value instanceof _ParseRelation2.default)) { - throw new Error('Called relation() on non-relation field ' + attr); - } - value._ensureParentAndKey(this, attr); - return value; - } - return new _ParseRelation2.default(this, attr); - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'escape', - value: function (attr) { - var val = this.attributes[attr]; - if (val == null) { - return ''; - } - - if (typeof val !== 'string') { - if (typeof val.toString !== 'function') { - return ''; - } - val = val.toString(); - } - return (0, _escape3.default)(val); - } - - /** - * Returns true if the attribute contains a value that is not - * null or undefined. - * @method has - * @param {String} attr The string name of the attribute. - * @return {Boolean} - */ - - }, { - key: 'has', - value: function (attr) { - var attributes = this.attributes; - if (attributes.hasOwnProperty(attr)) { - return attributes[attr] != null; - } - return false; - } - - /** - * Sets a hash of model attributes on the object. - * - *

                          You can call it with an object containing keys and values, or with one - * key and value. For example:

                          -     *   gameTurn.set({
                          -     *     player: player1,
                          -     *     diceRoll: 2
                          -     *   }, {
                          -     *     error: function(gameTurnAgain, error) {
                          -     *       // The set failed validation.
                          -     *     }
                          -     *   });
                          -     *
                          -     *   game.set("currentPlayer", player2, {
                          -     *     error: function(gameTurnAgain, error) {
                          -     *       // The set failed validation.
                          -     *     }
                          -     *   });
                          -     *
                          -     *   game.set("finished", true);

                          - * - * @method set - * @param {String} key The key to set. - * @param {} value The value to give it. - * @param {Object} options A set of options for the set. - * The only supported option is error. - * @return {Boolean} true if the set succeeded. - */ - - }, { - key: 'set', - value: function (key, value, options) { - var changes = {}; - var newOps = {}; - if (key && (typeof key === 'undefined' ? 'undefined' : (0, _typeof3.default)(key)) === 'object') { - changes = key; - options = value; - } else if (typeof key === 'string') { - changes[key] = value; - } else { - return this; - } - - options = options || {}; - var readonly = []; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var k in changes) { - if (k === 'createdAt' || k === 'updatedAt') { - // This property is read-only, but for legacy reasons we silently - // ignore it - continue; - } - if (readonly.indexOf(k) > -1) { - throw new Error('Cannot modify readonly attribute: ' + k); - } - if (options.unset) { - newOps[k] = new _ParseOp.UnsetOp(); - } else if (changes[k] instanceof _ParseOp.Op) { - newOps[k] = changes[k]; - } else if (changes[k] && (0, _typeof3.default)(changes[k]) === 'object' && typeof changes[k].__op === 'string') { - newOps[k] = (0, _ParseOp.opFromJSON)(changes[k]); - } else if (k === 'objectId' || k === 'id') { - if (typeof changes[k] === 'string') { - this.id = changes[k]; - } - } else if (k === 'ACL' && (0, _typeof3.default)(changes[k]) === 'object' && !(changes[k] instanceof _ParseACL2.default)) { - newOps[k] = new _ParseOp.SetOp(new _ParseACL2.default(changes[k])); - } else { - newOps[k] = new _ParseOp.SetOp(changes[k]); - } - } - - // Calculate new values - var currentAttributes = this.attributes; - var newValues = {}; - for (var attr in newOps) { - if (newOps[attr] instanceof _ParseOp.RelationOp) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); - } else if (!(newOps[attr] instanceof _ParseOp.UnsetOp)) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); - } - } - - // Validate changes - if (!options.ignoreValidation) { - var validation = this.validate(newValues); - if (validation) { - if (typeof options.error === 'function') { - options.error(this, validation); - } - return false; - } - } - - // Consolidate Ops - var pendingOps = this._getPendingOps(); - var last = pendingOps.length - 1; - var stateController = _CoreManager2.default.getObjectStateController(); - for (var attr in newOps) { - var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); - stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); - } - - return this; - } - - /** - * Remove an attribute from the model. This is a noop if the attribute doesn't - * exist. - * @method unset - * @param {String} attr The string name of an attribute. - */ - - }, { - key: 'unset', - value: function (attr, options) { - options = options || {}; - options.unset = true; - return this.set(attr, null, options); - } - - /** - * Atomically increments the value of the given attribute the next time the - * object is saved. If no amount is specified, 1 is used by default. - * - * @method increment - * @param attr {String} The key. - * @param amount {Number} The amount to increment by (optional). - */ - - }, { - key: 'increment', - value: function (attr, amount) { - if (typeof amount === 'undefined') { - amount = 1; - } - if (typeof amount !== 'number') { - throw new Error('Cannot increment by a non-numeric amount.'); - } - return this.set(attr, new _ParseOp.IncrementOp(amount)); - } - - /** - * Atomically add an object to the end of the array associated with a given - * key. - * @method add - * @param attr {String} The key. - * @param item {} The item to add. - */ - - }, { - key: 'add', - value: function (attr, item) { - return this.set(attr, new _ParseOp.AddOp([item])); - } - - /** - * Atomically add an object to the array associated with a given key, only - * if it is not already present in the array. The position of the insert is - * not guaranteed. - * - * @method addUnique - * @param attr {String} The key. - * @param item {} The object to add. - */ - - }, { - key: 'addUnique', - value: function (attr, item) { - return this.set(attr, new _ParseOp.AddUniqueOp([item])); - } - - /** - * Atomically remove all instances of an object from the array associated - * with a given key. - * - * @method remove - * @param attr {String} The key. - * @param item {} The object to remove. - */ - - }, { - key: 'remove', - value: function (attr, item) { - return this.set(attr, new _ParseOp.RemoveOp([item])); - } - - /** - * Returns an instance of a subclass of Parse.Op describing what kind of - * modification has been performed on this field since the last time it was - * saved. For example, after calling object.increment("x"), calling - * object.op("x") would return an instance of Parse.Op.Increment. - * - * @method op - * @param attr {String} The key. - * @returns {Parse.Op} The operation, or undefined if none. - */ - - }, { - key: 'op', - value: function (attr) { - var pending = this._getPendingOps(); - for (var i = pending.length; i--;) { - if (pending[i][attr]) { - return pending[i][attr]; - } - } - } - - /** - * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() - * @method clone - * @return {Parse.Object} - */ - - }, { - key: 'clone', - value: function () { - var clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - var attributes = this.attributes; - if (typeof this.constructor.readOnlyAttributes === 'function') { - var readonly = this.constructor.readOnlyAttributes() || []; - // Attributes are frozen, so we have to rebuild an object, - // rather than delete readonly keys - var copy = {}; - for (var a in attributes) { - if (readonly.indexOf(a) < 0) { - copy[a] = attributes[a]; - } - } - attributes = copy; - } - if (clone.set) { - clone.set(attributes); - } - return clone; - } - - /** - * Creates a new instance of this object. Not to be confused with clone() - * @method newInstance - * @return {Parse.Object} - */ - - }, { - key: 'newInstance', - value: function () { - var clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - clone.id = this.id; - if (singleInstance) { - // Just return an object with the right id - return clone; - } - - var stateController = _CoreManager2.default.getObjectStateController(); - if (stateController) { - stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); - } - return clone; - } - - /** - * Returns true if this object has never been saved to Parse. - * @method isNew - * @return {Boolean} - */ - - }, { - key: 'isNew', - value: function () { - return !this.id; - } - - /** - * Returns true if this object was created by the Parse server when the - * object might have already been there (e.g. in the case of a Facebook - * login) - * @method existed - * @return {Boolean} - */ - - }, { - key: 'existed', - value: function () { - if (!this.id) { - return false; - } - var stateController = _CoreManager2.default.getObjectStateController(); - var state = stateController.getState(this._getStateIdentifier()); - if (state) { - return state.existed; - } - return false; - } - - /** - * Checks if the model is currently in a valid state. - * @method isValid - * @return {Boolean} - */ - - }, { - key: 'isValid', - value: function () { - return !this.validate(this.attributes); - } - - /** - * You should not call this function directly unless you subclass - * Parse.Object, in which case you can override this method - * to provide additional validation on set and - * save. Your implementation should return - * - * @method validate - * @param {Object} attrs The current data to validate. - * @return {} False if the data is valid. An error object otherwise. - * @see Parse.Object#set - */ - - }, { - key: 'validate', - value: function (attrs) { - if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof _ParseACL2.default)) { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'ACL must be a Parse ACL.'); - } - for (var key in attrs) { - if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { - return new _ParseError2.default(_ParseError2.default.INVALID_KEY_NAME); - } - } - return false; - } - - /** - * Returns the ACL for this object. - * @method getACL - * @returns {Parse.ACL} An instance of Parse.ACL. - * @see Parse.Object#get - */ - - }, { - key: 'getACL', - value: function () { - var acl = this.get('ACL'); - if (acl instanceof _ParseACL2.default) { - return acl; - } - return null; - } - - /** - * Sets the ACL to be used for this object. - * @method setACL - * @param {Parse.ACL} acl An instance of Parse.ACL. - * @param {Object} options Optional Backbone-like options object to be - * passed in to set. - * @return {Boolean} Whether the set passed validation. - * @see Parse.Object#set - */ - - }, { - key: 'setACL', - value: function (acl, options) { - return this.set('ACL', acl, options); - } - - /** - * Clears any changes to this object made since the last call to save() - * @method revert - */ - - }, { - key: 'revert', - value: function () { - this._clearPendingOps(); - } - - /** - * Clears all attributes on a model - * @method clear - */ - - }, { - key: 'clear', - value: function () { - var attributes = this.attributes; - var erasable = {}; - var readonly = ['createdAt', 'updatedAt']; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var attr in attributes) { - if (readonly.indexOf(attr) < 0) { - erasable[attr] = true; - } - } - return this.set(erasable, { unset: true }); - } - - /** - * Fetch the model from the server. If the server's representation of the - * model differs from its current attributes, they will be overriden. - * - * @method fetch - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                            - *
                          • success: A Backbone-style success callback. - *
                          • error: An Backbone-style error callback. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * @return {Parse.Promise} A promise that is fulfilled when the fetch - * completes. - */ - - }, { - key: 'fetch', - value: function (options) { - options = options || {}; - var fetchOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - fetchOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - fetchOptions.sessionToken = options.sessionToken; - } - var controller = _CoreManager2.default.getObjectController(); - return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); - } - - /** - * Set a hash of model attributes, and save the model to the server. - * updatedAt will be updated when the request returns. - * You can either call it as:
                          -     *   object.save();
                          - * or
                          -     *   object.save(null, options);
                          - * or
                          -     *   object.save(attrs, options);
                          - * or
                          -     *   object.save(key, value, options);
                          - * - * For example,
                          -     *   gameTurn.save({
                          -     *     player: "Jake Cutter",
                          -     *     diceRoll: 2
                          -     *   }, {
                          -     *     success: function(gameTurnAgain) {
                          -     *       // The save was successful.
                          -     *     },
                          -     *     error: function(gameTurnAgain, error) {
                          -     *       // The save failed.  Error is an instance of Parse.Error.
                          -     *     }
                          -     *   });
                          - * or with promises:
                          -     *   gameTurn.save({
                          -     *     player: "Jake Cutter",
                          -     *     diceRoll: 2
                          -     *   }).then(function(gameTurnAgain) {
                          -     *     // The save was successful.
                          -     *   }, function(error) {
                          -     *     // The save failed.  Error is an instance of Parse.Error.
                          -     *   });
                          - * - * @method save - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                            - *
                          • success: A Backbone-style success callback. - *
                          • error: An Backbone-style error callback. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * @return {Parse.Promise} A promise that is fulfilled when the save - * completes. - */ - - }, { - key: 'save', - value: function (arg1, arg2, arg3) { - var _this = this; - - var attrs; - var options; - if ((typeof arg1 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg1)) === 'object' || typeof arg1 === 'undefined') { - attrs = arg1; - if ((typeof arg2 === 'undefined' ? 'undefined' : (0, _typeof3.default)(arg2)) === 'object') { - options = arg2; - } - } else { - attrs = {}; - attrs[arg1] = arg2; - options = arg3; - } - - // Support save({ success: function() {}, error: function() {} }) - if (!options && attrs) { - options = {}; - if (typeof attrs.success === 'function') { - options.success = attrs.success; - delete attrs.success; - } - if (typeof attrs.error === 'function') { - options.error = attrs.error; - delete attrs.error; - } - } - - if (attrs) { - var validation = this.validate(attrs); - if (validation) { - if (options && typeof options.error === 'function') { - options.error(this, validation); - } - return _ParsePromise2.default.error(validation); - } - this.set(attrs, options); - } - - options = options || {}; - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = !!options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { - saveOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getObjectController(); - var unsaved = (0, _unsavedChildren2.default)(this); - return controller.save(unsaved, saveOptions).then(function () { - return controller.save(_this, saveOptions); - })._thenRunCallbacks(options, this); - } - - /** - * Destroy this model on the server if it was already persisted. - * If `wait: true` is passed, waits for the server to respond - * before removal. - * - * @method destroy - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                            - *
                          • success: A Backbone-style success callback - *
                          • error: An Backbone-style error callback. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * @return {Parse.Promise} A promise that is fulfilled when the destroy - * completes. - */ - - }, { - key: 'destroy', - value: function (options) { - options = options || {}; - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - if (!this.id) { - return _ParsePromise2.default.as()._thenRunCallbacks(options); - } - return _CoreManager2.default.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); - } - - /** Static methods **/ - - }, { - key: 'attributes', - get: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - return (0, _freeze2.default)(stateController.estimateAttributes(this._getStateIdentifier())); - } - - /** - * The first time this object was saved on the server. - * @property createdAt - * @type Date - */ - - }, { - key: 'createdAt', - get: function () { - return this._getServerData().createdAt; - } - - /** - * The last time this object was updated on the server. - * @property updatedAt - * @type Date - */ - - }, { - key: 'updatedAt', - get: function () { - return this._getServerData().updatedAt; - } - }], [{ - key: '_clearAllState', - value: function () { - var stateController = _CoreManager2.default.getObjectStateController(); - stateController.clearAllState(); - } - - /** - * Fetches the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                          -     *   Parse.Object.fetchAll([object1, object2, ...], {
                          -     *     success: function(list) {
                          -     *       // All the objects were fetched.
                          -     *     },
                          -     *     error: function(error) {
                          -     *       // An error occurred while fetching one of the objects.
                          -     *     },
                          -     *   });
                          -     * 
                          - * - * @method fetchAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                            - *
                          • success: A Backbone-style success callback. - *
                          • error: An Backbone-style error callback. - *
                          - */ - - }, { - key: 'fetchAll', - value: function (list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); - } - - /** - * Fetches the given list of Parse.Object if needed. - * If any error is encountered, stops and calls the error handler. - * - *
                          -     *   Parse.Object.fetchAllIfNeeded([object1, ...], {
                          -     *     success: function(list) {
                          -     *       // Objects were fetched and updated.
                          -     *     },
                          -     *     error: function(error) {
                          -     *       // An error occurred while fetching one of the objects.
                          -     *     },
                          -     *   });
                          -     * 
                          - * - * @method fetchAllIfNeeded - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                            - *
                          • success: A Backbone-style success callback. - *
                          • error: An Backbone-style error callback. - *
                          - */ - - }, { - key: 'fetchAllIfNeeded', - value: function (list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); - } - - /** - * Destroy the given list of models on the server if it was already persisted. - * - *

                          Unlike saveAll, if an error occurs while deleting an individual model, - * this method will continue trying to delete the rest of the models if - * possible, except in the case of a fatal error like a connection error. - * - *

                          In particular, the Parse.Error object returned in the case of error may - * be one of two types: - * - *

                            - *
                          • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an - * array of other Parse.Error objects. Each error object in this array - * has an "object" property that references the object that could not be - * deleted (for instance, because that object could not be found).
                          • - *
                          • A non-aggregate Parse.Error. This indicates a serious error that - * caused the delete operation to be aborted partway through (for - * instance, a connection failure in the middle of the delete).
                          • - *
                          - * - *
                          -     *   Parse.Object.destroyAll([object1, object2, ...], {
                          -     *     success: function() {
                          -     *       // All the objects were deleted.
                          -     *     },
                          -     *     error: function(error) {
                          -     *       // An error occurred while deleting one or more of the objects.
                          -     *       // If this is an aggregate error, then we can inspect each error
                          -     *       // object individually to determine the reason why a particular
                          -     *       // object was not deleted.
                          -     *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
                          -     *         for (var i = 0; i < error.errors.length; i++) {
                          -     *           console.log("Couldn't delete " + error.errors[i].object.id +
                          -     *             "due to " + error.errors[i].message);
                          -     *         }
                          -     *       } else {
                          -     *         console.log("Delete aborted because of " + error.message);
                          -     *       }
                          -     *     },
                          -     *   });
                          -     * 
                          - * - * @method destroyAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                            - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * @return {Parse.Promise} A promise that is fulfilled when the destroyAll - * completes. - */ - - }, { - key: 'destroyAll', - value: function (list, options) { - var options = options || {}; - - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); - } - - /** - * Saves the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                          -     *   Parse.Object.saveAll([object1, object2, ...], {
                          -     *     success: function(list) {
                          -     *       // All the objects were saved.
                          -     *     },
                          -     *     error: function(error) {
                          -     *       // An error occurred while saving one of the objects.
                          -     *     },
                          -     *   });
                          -     * 
                          - * - * @method saveAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                            - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - */ - - }, { - key: 'saveAll', - value: function (list, options) { - var options = options || {}; - - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - saveOptions.sessionToken = options.sessionToken; - } - return _CoreManager2.default.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); - } - - /** - * Creates a reference to a subclass of Parse.Object with the given id. This - * does not exist on Parse.Object, only on subclasses. - * - *

                          A shortcut for:

                          -     *  var Foo = Parse.Object.extend("Foo");
                          -     *  var pointerToFoo = new Foo();
                          -     *  pointerToFoo.id = "myObjectId";
                          -     * 
                          - * - * @method createWithoutData - * @param {String} id The ID of the object to create a reference to. - * @static - * @return {Parse.Object} A Parse.Object reference. - */ - - }, { - key: 'createWithoutData', - value: function (id) { - var obj = new this(); - obj.id = id; - return obj; - } - - /** - * Creates a new instance of a Parse Object from a JSON representation. - * @method fromJSON - * @param {Object} json The JSON map of the Object's data - * @param {boolean} override In single instance mode, all old server data - * is overwritten if this is set to true - * @static - * @return {Parse.Object} A Parse.Object reference - */ - - }, { - key: 'fromJSON', - value: function (json, override) { - if (!json.className) { - throw new Error('Cannot create an object without a className'); - } - var constructor = classMap[json.className]; - var o = constructor ? new constructor() : new ParseObject(json.className); - var otherAttributes = {}; - for (var attr in json) { - if (attr !== 'className' && attr !== '__type') { - otherAttributes[attr] = json[attr]; - } - } - if (override) { - // id needs to be set before clearServerData can work - if (otherAttributes.objectId) { - o.id = otherAttributes.objectId; - } - var preserved = null; - if (typeof o._preserveFieldsOnFetch === 'function') { - preserved = o._preserveFieldsOnFetch(); - } - o._clearServerData(); - if (preserved) { - o._finishFetch(preserved); - } - } - o._finishFetch(otherAttributes); - if (json.objectId) { - o._setExisted(true); - } - return o; - } - - /** - * Registers a subclass of Parse.Object with a specific class name. - * When objects of that class are retrieved from a query, they will be - * instantiated with this subclass. - * This is only necessary when using ES6 subclassing. - * @method registerSubclass - * @param {String} className The class name of the subclass - * @param {Class} constructor The subclass - */ - - }, { - key: 'registerSubclass', - value: function (className, constructor) { - if (typeof className !== 'string') { - throw new TypeError('The first argument must be a valid class name.'); - } - if (typeof constructor === 'undefined') { - throw new TypeError('You must supply a subclass constructor.'); - } - if (typeof constructor !== 'function') { - throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); - } - classMap[className] = constructor; - if (!constructor.className) { - constructor.className = className; - } - } - - /** - * Creates a new subclass of Parse.Object for the given Parse class name. - * - *

                          Every extension of a Parse class will inherit from the most recent - * previous extension of that class. When a Parse.Object is automatically - * created by parsing JSON, it will use the most recent extension of that - * class.

                          - * - *

                          You should call either:

                          -     *     var MyClass = Parse.Object.extend("MyClass", {
                          -     *         Instance methods,
                          -     *         initialize: function(attrs, options) {
                          -     *             this.someInstanceProperty = [],
                          -     *             Other instance properties
                          -     *         }
                          -     *     }, {
                          -     *         Class properties
                          -     *     });
                          - * or, for Backbone compatibility:
                          -     *     var MyClass = Parse.Object.extend({
                          -     *         className: "MyClass",
                          -     *         Instance methods,
                          -     *         initialize: function(attrs, options) {
                          -     *             this.someInstanceProperty = [],
                          -     *             Other instance properties
                          -     *         }
                          -     *     }, {
                          -     *         Class properties
                          -     *     });

                          - * - * @method extend - * @param {String} className The name of the Parse class backing this model. - * @param {Object} protoProps Instance properties to add to instances of the - * class returned from this method. - * @param {Object} classProps Class properties to add the class returned from - * this method. - * @return {Class} A new subclass of Parse.Object. - */ - - }, { - key: 'extend', - value: function (className, protoProps, classProps) { - if (typeof className !== 'string') { - if (className && typeof className.className === 'string') { - return ParseObject.extend(className.className, className, protoProps); - } else { - throw new Error('Parse.Object.extend\'s first argument should be the className.'); - } - } - var adjustedClassName = className; - - if (adjustedClassName === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { - adjustedClassName = '_User'; - } - - var parentProto = ParseObject.prototype; - if (this.hasOwnProperty('__super__') && this.__super__) { - parentProto = this.prototype; - } else if (classMap[adjustedClassName]) { - parentProto = classMap[adjustedClassName].prototype; - } - var ParseObjectSubclass = function (attributes, options) { - this.className = adjustedClassName; - this._objCount = objectCount++; - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!this.set(attributes || {}, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - }; - ParseObjectSubclass.className = adjustedClassName; - ParseObjectSubclass.__super__ = parentProto; - - ParseObjectSubclass.prototype = (0, _create2.default)(parentProto, { - constructor: { - value: ParseObjectSubclass, - enumerable: false, - writable: true, - configurable: true - } - }); - - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseObjectSubclass.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseObjectSubclass, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - ParseObjectSubclass.extend = function (name, protoProps, classProps) { - if (typeof name === 'string') { - return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); - } - return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); - }; - ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; - - classMap[adjustedClassName] = ParseObjectSubclass; - return ParseObjectSubclass; - } - - /** - * Enable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * This is disabled by default in server environments, since it can lead to - * security issues. - * @method enableSingleInstance - */ - - }, { - key: 'enableSingleInstance', - value: function () { - singleInstance = true; - _CoreManager2.default.setObjectStateController(SingleInstanceStateController); - } - - /** - * Disable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * When disabled, you can have two instances of the same object in memory - * without them sharing attributes. - * @method disableSingleInstance - */ - - }, { - key: 'disableSingleInstance', - value: function () { - singleInstance = false; - _CoreManager2.default.setObjectStateController(UniqueInstanceStateController); - } - }]); - return ParseObject; -}(); - -exports.default = ParseObject; - -var DefaultController = { - fetch: function (target, forceFetch, options) { - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - var objs = []; - var ids = []; - var className = null; - var results = []; - var error = null; - target.forEach(function (el, i) { - if (error) { - return; - } - if (!className) { - className = el.className; - } - if (className !== el.className) { - error = new _ParseError2.default(_ParseError2.default.INVALID_CLASS_NAME, 'All objects should be of the same class'); - } - if (!el.id) { - error = new _ParseError2.default(_ParseError2.default.MISSING_OBJECT_ID, 'All objects must have an ID'); - } - if (forceFetch || (0, _keys2.default)(el._getServerData()).length === 0) { - ids.push(el.id); - objs.push(el); - } - results.push(el); - }); - if (error) { - return _ParsePromise2.default.error(error); - } - var query = new _ParseQuery2.default(className); - query.containedIn('objectId', ids); - query._limit = ids.length; - return query.find(options).then(function (objects) { - var idMap = {}; - objects.forEach(function (o) { - idMap[o.id] = o; - }); - for (var i = 0; i < objs.length; i++) { - var obj = objs[i]; - if (!obj || !obj.id || !idMap[obj.id]) { - if (forceFetch) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); - } - } - } - if (!singleInstance) { - // If single instance objects are disabled, we need to replace the - for (var i = 0; i < results.length; i++) { - var obj = results[i]; - if (obj && obj.id && idMap[obj.id]) { - var id = obj.id; - obj._finishFetch(idMap[id].toJSON()); - results[i] = idMap[id]; - } - } - } - return _ParsePromise2.default.as(results); - }); - } else { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function (response, status, xhr) { - if (target instanceof ParseObject) { - target._clearPendingOps(); - target._clearServerData(); - target._finishFetch(response); - } - return target; - }); - } - }, - destroy: function (target, options) { - var RESTController = _CoreManager2.default.getRESTController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - var batches = [[]]; - target.forEach(function (obj) { - if (!obj.id) { - return; - } - batches[batches.length - 1].push(obj); - if (batches[batches.length - 1].length >= 20) { - batches.push([]); - } - }); - if (batches[batches.length - 1].length === 0) { - // If the last batch is empty, remove it - batches.pop(); - } - var deleteCompleted = _ParsePromise2.default.as(); - var errors = []; - batches.forEach(function (batch) { - deleteCompleted = deleteCompleted.then(function () { - return RESTController.request('POST', 'batch', { - requests: batch.map(function (obj) { - return { - method: 'DELETE', - path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), - body: {} - }; - }) - }, options).then(function (results) { - for (var i = 0; i < results.length; i++) { - if (results[i] && results[i].hasOwnProperty('error')) { - var err = new _ParseError2.default(results[i].error.code, results[i].error.error); - err.object = batch[i]; - errors.push(err); - } - } - }); - }); - }); - return deleteCompleted.then(function () { - if (errors.length) { - var aggregate = new _ParseError2.default(_ParseError2.default.AGGREGATE_ERROR); - aggregate.errors = errors; - return _ParsePromise2.default.error(aggregate); - } - return _ParsePromise2.default.as(target); - }); - } else if (target instanceof ParseObject) { - return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(function () { - return _ParsePromise2.default.as(target); - }); - } - return _ParsePromise2.default.as(target); - }, - save: function (target, options) { - var RESTController = _CoreManager2.default.getRESTController(); - var stateController = _CoreManager2.default.getObjectStateController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return _ParsePromise2.default.as([]); - } - - var unsaved = target.concat(); - for (var i = 0; i < target.length; i++) { - if (target[i] instanceof ParseObject) { - unsaved = unsaved.concat((0, _unsavedChildren2.default)(target[i], true)); - } - } - unsaved = (0, _unique2.default)(unsaved); - - var filesSaved = _ParsePromise2.default.as(); - var pending = []; - unsaved.forEach(function (el) { - if (el instanceof _ParseFile2.default) { - filesSaved = filesSaved.then(function () { - return el.save(); - }); - } else if (el instanceof ParseObject) { - pending.push(el); - } - }); - - return filesSaved.then(function () { - var objectError = null; - return _ParsePromise2.default._continueWhile(function () { - return pending.length > 0; - }, function () { - var batch = []; - var nextPending = []; - pending.forEach(function (el) { - if (batch.length < 20 && (0, _canBeSerialized2.default)(el)) { - batch.push(el); - } else { - nextPending.push(el); - } - }); - pending = nextPending; - if (batch.length < 1) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); - } - - // Queue up tasks for each object in the batch. - // When every task is ready, the API request will execute - var batchReturned = new _ParsePromise2.default(); - var batchReady = []; - var batchTasks = []; - batch.forEach(function (obj, index) { - var ready = new _ParsePromise2.default(); - batchReady.push(ready); - - stateController.pushPendingState(obj._getStateIdentifier()); - batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { - ready.resolve(); - return batchReturned.then(function (responses, status) { - if (responses[index].hasOwnProperty('success')) { - obj._handleSaveResponse(responses[index].success, status); - } else { - if (!objectError && responses[index].hasOwnProperty('error')) { - var serverError = responses[index].error; - objectError = new _ParseError2.default(serverError.code, serverError.error); - // Cancel the rest of the save - pending = []; - } - obj._handleSaveError(); - } - }); - })); - }); - - _ParsePromise2.default.when(batchReady).then(function () { - // Kick off the batch request - return RESTController.request('POST', 'batch', { - requests: batch.map(function (obj) { - var params = obj._getSaveParams(); - params.path = getServerUrlPath() + params.path; - return params; - }) - }, options); - }).then(function (response, status, xhr) { - batchReturned.resolve(response, status); - }); - - return _ParsePromise2.default.when(batchTasks); - }).then(function () { - if (objectError) { - return _ParsePromise2.default.error(objectError); - } - return _ParsePromise2.default.as(target); - }); - }); - } else if (target instanceof ParseObject) { - // copying target lets Flow guarantee the pointer isn't modified elsewhere - var targetCopy = target; - var task = function () { - var params = targetCopy._getSaveParams(); - return RESTController.request(params.method, params.path, params.body, options).then(function (response, status) { - targetCopy._handleSaveResponse(response, status); - }, function (error) { - targetCopy._handleSaveError(); - return _ParsePromise2.default.error(error); - }); - }; - - stateController.pushPendingState(target._getStateIdentifier()); - return stateController.enqueueTask(target._getStateIdentifier(), task).then(function () { - return target; - }, function (error) { - return _ParsePromise2.default.error(error); - }); - } - return _ParsePromise2.default.as(); - } -}; - -_CoreManager2.default.setObjectController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseOp.js b/lib/node/ParseOp.js deleted file mode 100644 index 1eba19303..000000000 --- a/lib/node/ParseOp.js +++ /dev/null @@ -1,579 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.RelationOp = exports.RemoveOp = exports.AddUniqueOp = exports.AddOp = exports.IncrementOp = exports.UnsetOp = exports.SetOp = exports.Op = undefined; - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -exports.opFromJSON = opFromJSON; - -var _arrayContainsObject = require('./arrayContainsObject'); - -var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); - -var _decode = require('./decode'); - -var _decode2 = _interopRequireDefault(_decode); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -var _unique = require('./unique'); - -var _unique2 = _interopRequireDefault(_unique); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function opFromJSON(json) { - if (!json || !json.__op) { - return null; - } - switch (json.__op) { - case 'Delete': - return new UnsetOp(); - case 'Increment': - return new IncrementOp(json.amount); - case 'Add': - return new AddOp((0, _decode2.default)(json.objects)); - case 'AddUnique': - return new AddUniqueOp((0, _decode2.default)(json.objects)); - case 'Remove': - return new RemoveOp((0, _decode2.default)(json.objects)); - case 'AddRelation': - var toAdd = (0, _decode2.default)(json.objects); - if (!Array.isArray(toAdd)) { - return new RelationOp([], []); - } - return new RelationOp(toAdd, []); - case 'RemoveRelation': - var toRemove = (0, _decode2.default)(json.objects); - if (!Array.isArray(toRemove)) { - return new RelationOp([], []); - } - return new RelationOp([], toRemove); - case 'Batch': - var toAdd = []; - var toRemove = []; - for (var i = 0; i < json.ops.length; i++) { - if (json.ops[i].__op === 'AddRelation') { - toAdd = toAdd.concat((0, _decode2.default)(json.ops[i].objects)); - } else if (json.ops[i].__op === 'RemoveRelation') { - toRemove = toRemove.concat((0, _decode2.default)(json.ops[i].objects)); - } - } - return new RelationOp(toAdd, toRemove); - } - return null; -} - -var Op = exports.Op = function () { - function Op() { - (0, _classCallCheck3.default)(this, Op); - } - - (0, _createClass3.default)(Op, [{ - key: 'applyTo', - - // Empty parent class - value: function (value) {} - }, { - key: 'mergeWith', - value: function (previous) {} - }, { - key: 'toJSON', - value: function () {} - }]); - return Op; -}(); - -var SetOp = exports.SetOp = function (_Op) { - (0, _inherits3.default)(SetOp, _Op); - - function SetOp(value) { - (0, _classCallCheck3.default)(this, SetOp); - - var _this = (0, _possibleConstructorReturn3.default)(this, (SetOp.__proto__ || (0, _getPrototypeOf2.default)(SetOp)).call(this)); - - _this._value = value; - return _this; - } - - (0, _createClass3.default)(SetOp, [{ - key: 'applyTo', - value: function (value) { - return this._value; - } - }, { - key: 'mergeWith', - value: function (previous) { - return new SetOp(this._value); - } - }, { - key: 'toJSON', - value: function () { - return (0, _encode2.default)(this._value, false, true); - } - }]); - return SetOp; -}(Op); - -var UnsetOp = exports.UnsetOp = function (_Op2) { - (0, _inherits3.default)(UnsetOp, _Op2); - - function UnsetOp() { - (0, _classCallCheck3.default)(this, UnsetOp); - return (0, _possibleConstructorReturn3.default)(this, (UnsetOp.__proto__ || (0, _getPrototypeOf2.default)(UnsetOp)).apply(this, arguments)); - } - - (0, _createClass3.default)(UnsetOp, [{ - key: 'applyTo', - value: function (value) { - return undefined; - } - }, { - key: 'mergeWith', - value: function (previous) { - return new UnsetOp(); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Delete' }; - } - }]); - return UnsetOp; -}(Op); - -var IncrementOp = exports.IncrementOp = function (_Op3) { - (0, _inherits3.default)(IncrementOp, _Op3); - - function IncrementOp(amount) { - (0, _classCallCheck3.default)(this, IncrementOp); - - var _this3 = (0, _possibleConstructorReturn3.default)(this, (IncrementOp.__proto__ || (0, _getPrototypeOf2.default)(IncrementOp)).call(this)); - - if (typeof amount !== 'number') { - throw new TypeError('Increment Op must be initialized with a numeric amount.'); - } - _this3._amount = amount; - return _this3; - } - - (0, _createClass3.default)(IncrementOp, [{ - key: 'applyTo', - value: function (value) { - if (typeof value === 'undefined') { - return this._amount; - } - if (typeof value !== 'number') { - throw new TypeError('Cannot increment a non-numeric value.'); - } - return this._amount + value; - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._amount); - } - if (previous instanceof IncrementOp) { - return new IncrementOp(this.applyTo(previous._amount)); - } - throw new Error('Cannot merge Increment Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Increment', amount: this._amount }; - } - }]); - return IncrementOp; -}(Op); - -var AddOp = exports.AddOp = function (_Op4) { - (0, _inherits3.default)(AddOp, _Op4); - - function AddOp(value) { - (0, _classCallCheck3.default)(this, AddOp); - - var _this4 = (0, _possibleConstructorReturn3.default)(this, (AddOp.__proto__ || (0, _getPrototypeOf2.default)(AddOp)).call(this)); - - _this4._value = Array.isArray(value) ? value : [value]; - return _this4; - } - - (0, _createClass3.default)(AddOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return this._value; - } - if (Array.isArray(value)) { - return value.concat(this._value); - } - throw new Error('Cannot add elements to a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddOp) { - return new AddOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge Add Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Add', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return AddOp; -}(Op); - -var AddUniqueOp = exports.AddUniqueOp = function (_Op5) { - (0, _inherits3.default)(AddUniqueOp, _Op5); - - function AddUniqueOp(value) { - (0, _classCallCheck3.default)(this, AddUniqueOp); - - var _this5 = (0, _possibleConstructorReturn3.default)(this, (AddUniqueOp.__proto__ || (0, _getPrototypeOf2.default)(AddUniqueOp)).call(this)); - - _this5._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); - return _this5; - } - - (0, _createClass3.default)(AddUniqueOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return this._value || []; - } - if (Array.isArray(value)) { - // copying value lets Flow guarantee the pointer isn't modified elsewhere - var valueCopy = value; - var toAdd = []; - this._value.forEach(function (v) { - if (v instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(valueCopy, v)) { - toAdd.push(v); - } - } else { - if (valueCopy.indexOf(v) < 0) { - toAdd.push(v); - } - } - }); - return value.concat(toAdd); - } - throw new Error('Cannot add elements to a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddUniqueOp) { - return new AddUniqueOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge AddUnique Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'AddUnique', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return AddUniqueOp; -}(Op); - -var RemoveOp = exports.RemoveOp = function (_Op6) { - (0, _inherits3.default)(RemoveOp, _Op6); - - function RemoveOp(value) { - (0, _classCallCheck3.default)(this, RemoveOp); - - var _this6 = (0, _possibleConstructorReturn3.default)(this, (RemoveOp.__proto__ || (0, _getPrototypeOf2.default)(RemoveOp)).call(this)); - - _this6._value = (0, _unique2.default)(Array.isArray(value) ? value : [value]); - return _this6; - } - - (0, _createClass3.default)(RemoveOp, [{ - key: 'applyTo', - value: function (value) { - if (value == null) { - return []; - } - if (Array.isArray(value)) { - var i = value.indexOf(this._value); - var removed = value.concat([]); - for (var i = 0; i < this._value.length; i++) { - var index = removed.indexOf(this._value[i]); - while (index > -1) { - removed.splice(index, 1); - index = removed.indexOf(this._value[i]); - } - if (this._value[i] instanceof _ParseObject2.default && this._value[i].id) { - for (var j = 0; j < removed.length; j++) { - if (removed[j] instanceof _ParseObject2.default && this._value[i].id === removed[j].id) { - removed.splice(j, 1); - j--; - } - } - } - } - return removed; - } - throw new Error('Cannot remove elements from a non-array value'); - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new UnsetOp(); - } - if (previous instanceof RemoveOp) { - var uniques = previous._value.concat([]); - for (var i = 0; i < this._value.length; i++) { - if (this._value[i] instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(uniques, this._value[i])) { - uniques.push(this._value[i]); - } - } else { - if (uniques.indexOf(this._value[i]) < 0) { - uniques.push(this._value[i]); - } - } - } - return new RemoveOp(uniques); - } - throw new Error('Cannot merge Remove Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - return { __op: 'Remove', objects: (0, _encode2.default)(this._value, false, true) }; - } - }]); - return RemoveOp; -}(Op); - -var RelationOp = exports.RelationOp = function (_Op7) { - (0, _inherits3.default)(RelationOp, _Op7); - - function RelationOp(adds, removes) { - (0, _classCallCheck3.default)(this, RelationOp); - - var _this7 = (0, _possibleConstructorReturn3.default)(this, (RelationOp.__proto__ || (0, _getPrototypeOf2.default)(RelationOp)).call(this)); - - _this7._targetClassName = null; - - if (Array.isArray(adds)) { - _this7.relationsToAdd = (0, _unique2.default)(adds.map(_this7._extractId, _this7)); - } - - if (Array.isArray(removes)) { - _this7.relationsToRemove = (0, _unique2.default)(removes.map(_this7._extractId, _this7)); - } - return _this7; - } - - (0, _createClass3.default)(RelationOp, [{ - key: '_extractId', - value: function (obj) { - if (typeof obj === 'string') { - return obj; - } - if (!obj.id) { - throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); - } - if (!this._targetClassName) { - this._targetClassName = obj.className; - } - if (this._targetClassName !== obj.className) { - throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); - } - return obj.id; - } - }, { - key: 'applyTo', - value: function (value, object, key) { - if (!value) { - if (!object || !key) { - throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); - } - var parent = new _ParseObject2.default(object.className); - if (object.id && object.id.indexOf('local') === 0) { - parent._localId = object.id; - } else if (object.id) { - parent.id = object.id; - } - var relation = new _ParseRelation2.default(parent, key); - relation.targetClassName = this._targetClassName; - return relation; - } - if (value instanceof _ParseRelation2.default) { - if (this._targetClassName) { - if (value.targetClassName) { - if (this._targetClassName !== value.targetClassName) { - throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); - } - } else { - value.targetClassName = this._targetClassName; - } - } - return value; - } else { - throw new Error('Relation cannot be applied to a non-relation field'); - } - } - }, { - key: 'mergeWith', - value: function (previous) { - if (!previous) { - return this; - } else if (previous instanceof UnsetOp) { - throw new Error('You cannot modify a relation after deleting it.'); - } else if (previous instanceof RelationOp) { - if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { - throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); - } - var newAdd = previous.relationsToAdd.concat([]); - this.relationsToRemove.forEach(function (r) { - var index = newAdd.indexOf(r); - if (index > -1) { - newAdd.splice(index, 1); - } - }); - this.relationsToAdd.forEach(function (r) { - var index = newAdd.indexOf(r); - if (index < 0) { - newAdd.push(r); - } - }); - - var newRemove = previous.relationsToRemove.concat([]); - this.relationsToAdd.forEach(function (r) { - var index = newRemove.indexOf(r); - if (index > -1) { - newRemove.splice(index, 1); - } - }); - this.relationsToRemove.forEach(function (r) { - var index = newRemove.indexOf(r); - if (index < 0) { - newRemove.push(r); - } - }); - - var newRelation = new RelationOp(newAdd, newRemove); - newRelation._targetClassName = this._targetClassName; - return newRelation; - } - throw new Error('Cannot merge Relation Op with the previous Op'); - } - }, { - key: 'toJSON', - value: function () { - var _this8 = this; - - var idToPointer = function (id) { - return { - __type: 'Pointer', - className: _this8._targetClassName, - objectId: id - }; - }; - - var adds = null; - var removes = null; - var pointers = null; - - if (this.relationsToAdd.length > 0) { - pointers = this.relationsToAdd.map(idToPointer); - adds = { __op: 'AddRelation', objects: pointers }; - } - if (this.relationsToRemove.length > 0) { - pointers = this.relationsToRemove.map(idToPointer); - removes = { __op: 'RemoveRelation', objects: pointers }; - } - - if (adds && removes) { - return { __op: 'Batch', ops: [adds, removes] }; - } - - return adds || removes || {}; - } - }]); - return RelationOp; -}(Op); \ No newline at end of file diff --git a/lib/node/ParsePromise.js b/lib/node/ParsePromise.js deleted file mode 100644 index a79b4afee..000000000 --- a/lib/node/ParsePromise.js +++ /dev/null @@ -1,740 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getIterator2 = require('babel-runtime/core-js/get-iterator'); - -var _getIterator3 = _interopRequireDefault(_getIterator2); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var _isPromisesAPlusCompliant = true; - -/** - * A Promise is returned by async methods as a hook to provide callbacks to be - * called when the async task is fulfilled. - * - *

                          Typical usage would be like:

                          - *    query.find().then(function(results) {
                          - *      results[0].set("foo", "bar");
                          - *      return results[0].saveAsync();
                          - *    }).then(function(result) {
                          - *      console.log("Updated " + result.id);
                          - *    });
                          - * 

                          - * - * @class Parse.Promise - * @constructor - */ - -var ParsePromise = function () { - function ParsePromise(executor) { - (0, _classCallCheck3.default)(this, ParsePromise); - - this._resolved = false; - this._rejected = false; - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - - if (typeof executor === 'function') { - executor(this.resolve.bind(this), this.reject.bind(this)); - } - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method resolve - * @param {Object} result the result to pass to the callbacks. - */ - - (0, _createClass3.default)(ParsePromise, [{ - key: 'resolve', - value: function () { - if (this._resolved || this._rejected) { - throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._resolved = true; - - for (var _len = arguments.length, results = Array(_len), _key = 0; _key < _len; _key++) { - results[_key] = arguments[_key]; - } - - this._result = results; - for (var i = 0; i < this._resolvedCallbacks.length; i++) { - this._resolvedCallbacks[i].apply(this, results); - } - - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method reject - * @param {Object} error the error to pass to the callbacks. - */ - - }, { - key: 'reject', - value: function (error) { - if (this._resolved || this._rejected) { - throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._rejected = true; - this._error = error; - for (var i = 0; i < this._rejectedCallbacks.length; i++) { - this._rejectedCallbacks[i](error); - } - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Adds callbacks to be called when this promise is fulfilled. Returns a new - * Promise that will be fulfilled when the callback is complete. It allows - * chaining. If the callback itself returns a Promise, then the one returned - * by "then" will not be fulfilled until that one returned by the callback - * is fulfilled. - * @method then - * @param {Function} resolvedCallback Function that is called when this - * Promise is resolved. Once the callback is complete, then the Promise - * returned by "then" will also be fulfilled. - * @param {Function} rejectedCallback Function that is called when this - * Promise is rejected with an error. Once the callback is complete, then - * the promise returned by "then" with be resolved successfully. If - * rejectedCallback is null, or it returns a rejected Promise, then the - * Promise returned by "then" will be rejected with that error. - * @return {Parse.Promise} A new Promise that will be fulfilled after this - * Promise is fulfilled and either callback has completed. If the callback - * returned a Promise, then this Promise will not be fulfilled until that - * one is. - */ - - }, { - key: 'then', - value: function (resolvedCallback, rejectedCallback) { - var _this = this; - - var promise = new ParsePromise(); - - var wrappedResolvedCallback = function () { - for (var _len2 = arguments.length, results = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - results[_key2] = arguments[_key2]; - } - - if (typeof resolvedCallback === 'function') { - if (_isPromisesAPlusCompliant) { - try { - results = [resolvedCallback.apply(this, results)]; - } catch (e) { - results = [ParsePromise.error(e)]; - } - } else { - results = [resolvedCallback.apply(this, results)]; - } - } - if (results.length === 1 && ParsePromise.is(results[0])) { - results[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - promise.resolve.apply(promise, results); - } - }; - - var wrappedRejectedCallback = function (error) { - var result = []; - if (typeof rejectedCallback === 'function') { - if (_isPromisesAPlusCompliant) { - try { - result = [rejectedCallback(error)]; - } catch (e) { - result = [ParsePromise.error(e)]; - } - } else { - result = [rejectedCallback(error)]; - } - if (result.length === 1 && ParsePromise.is(result[0])) { - result[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - if (_isPromisesAPlusCompliant) { - promise.resolve.apply(promise, result); - } else { - promise.reject(result[0]); - } - } - } else { - promise.reject(error); - } - }; - - var runLater = function (fn) { - fn.call(); - }; - if (_isPromisesAPlusCompliant) { - if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { - runLater = function (fn) { - process.nextTick(fn); - }; - } else if (typeof setTimeout === 'function') { - runLater = function (fn) { - setTimeout(fn, 0); - }; - } - } - - if (this._resolved) { - runLater(function () { - wrappedResolvedCallback.apply(_this, _this._result); - }); - } else if (this._rejected) { - runLater(function () { - wrappedRejectedCallback(_this._error); - }); - } else { - this._resolvedCallbacks.push(wrappedResolvedCallback); - this._rejectedCallbacks.push(wrappedRejectedCallback); - } - - return promise; - } - - /** - * Add handlers to be called when the promise - * is either resolved or rejected - * @method always - */ - - }, { - key: 'always', - value: function (callback) { - return this.then(callback, callback); - } - - /** - * Add handlers to be called when the Promise object is resolved - * @method done - */ - - }, { - key: 'done', - value: function (callback) { - return this.then(callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * Alias for catch(). - * @method fail - */ - - }, { - key: 'fail', - value: function (callback) { - return this.then(null, callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * @method catch - */ - - }, { - key: 'catch', - value: function (callback) { - return this.then(null, callback); - } - - /** - * Run the given callbacks after this promise is fulfilled. - * @method _thenRunCallbacks - * @param optionsOrCallback {} A Backbone-style options callback, or a - * callback function. If this is an options object and contains a "model" - * attributes, that will be passed to error callbacks as the first argument. - * @param model {} If truthy, this will be passed as the first result of - * error callbacks. This is for Backbone-compatability. - * @return {Parse.Promise} A promise that will be resolved after the - * callbacks are run, with the same result as this. - */ - - }, { - key: '_thenRunCallbacks', - value: function (optionsOrCallback, model) { - var options = {}; - if (typeof optionsOrCallback === 'function') { - options.success = function (result) { - optionsOrCallback(result, null); - }; - options.error = function (error) { - optionsOrCallback(null, error); - }; - } else if ((typeof optionsOrCallback === 'undefined' ? 'undefined' : (0, _typeof3.default)(optionsOrCallback)) === 'object') { - if (typeof optionsOrCallback.success === 'function') { - options.success = optionsOrCallback.success; - } - if (typeof optionsOrCallback.error === 'function') { - options.error = optionsOrCallback.error; - } - } - - return this.then(function () { - for (var _len3 = arguments.length, results = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - results[_key3] = arguments[_key3]; - } - - if (options.success) { - options.success.apply(this, results); - } - return ParsePromise.as.apply(ParsePromise, arguments); - }, function (error) { - if (options.error) { - if (typeof model !== 'undefined') { - options.error(model, error); - } else { - options.error(error); - } - } - // By explicitly returning a rejected Promise, this will work with - // either jQuery or Promises/A+ semantics. - return ParsePromise.error(error); - }); - } - - /** - * Adds a callback function that should be called regardless of whether - * this promise failed or succeeded. The callback will be given either the - * array of results for its first argument, or the error as its second, - * depending on whether this Promise was rejected or resolved. Returns a - * new Promise, like "then" would. - * @method _continueWith - * @param {Function} continuation the callback. - */ - - }, { - key: '_continueWith', - value: function (continuation) { - return this.then(function () { - for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - args[_key4] = arguments[_key4]; - } - - return continuation(args, null); - }, function (error) { - return continuation(null, error); - }); - } - - /** - * Returns true iff the given object fulfils the Promise interface. - * @method is - * @param {Object} promise The object to test - * @static - * @return {Boolean} - */ - - }], [{ - key: 'is', - value: function (promise) { - return promise != null && typeof promise.then === 'function'; - } - - /** - * Returns a new promise that is resolved with a given value. - * @method as - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'as', - value: function () { - var promise = new ParsePromise(); - - for (var _len5 = arguments.length, values = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - values[_key5] = arguments[_key5]; - } - - promise.resolve.apply(promise, values); - return promise; - } - - /** - * Returns a new promise that is resolved with a given value. - * If that value is a thenable Promise (has a .then() prototype - * method), the new promise will be chained to the end of the - * value. - * @method resolve - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'resolve', - value: function (value) { - return new ParsePromise(function (resolve, reject) { - if (ParsePromise.is(value)) { - value.then(resolve, reject); - } else { - resolve(value); - } - }); - } - - /** - * Returns a new promise that is rejected with a given error. - * @method error - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'error', - value: function () { - var promise = new ParsePromise(); - - for (var _len6 = arguments.length, errors = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - errors[_key6] = arguments[_key6]; - } - - promise.reject.apply(promise, errors); - return promise; - } - - /** - * Returns a new promise that is rejected with a given error. - * This is an alias for Parse.Promise.error, for compliance with - * the ES6 implementation. - * @method reject - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'reject', - value: function () { - for (var _len7 = arguments.length, errors = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - errors[_key7] = arguments[_key7]; - } - - return ParsePromise.error.apply(null, errors); - } - - /** - * Returns a new promise that is fulfilled when all of the input promises - * are resolved. If any promise in the list fails, then the returned promise - * will be rejected with an array containing the error from each promise. - * If they all succeed, then the returned promise will succeed, with the - * results being the results of all the input - * promises. For example:
                          -     *   var p1 = Parse.Promise.as(1);
                          -     *   var p2 = Parse.Promise.as(2);
                          -     *   var p3 = Parse.Promise.as(3);
                          -     *
                          -     *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
                          -     *     console.log(r1);  // prints 1
                          -     *     console.log(r2);  // prints 2
                          -     *     console.log(r3);  // prints 3
                          -     *   });
                          - * - * The input promises can also be specified as an array:
                          -     *   var promises = [p1, p2, p3];
                          -     *   Parse.Promise.when(promises).then(function(results) {
                          -     *     console.log(results);  // prints [1,2,3]
                          -     *   });
                          -     * 
                          - * @method when - * @param {Array} promises a list of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'when', - value: function (promises) { - var objects; - var arrayArgument = Array.isArray(promises); - if (arrayArgument) { - objects = promises; - } else { - objects = arguments; - } - - var total = objects.length; - var hadError = false; - var results = []; - var returnValue = arrayArgument ? [results] : results; - var errors = []; - results.length = objects.length; - errors.length = objects.length; - - if (total === 0) { - return ParsePromise.as.apply(this, returnValue); - } - - var promise = new ParsePromise(); - - var resolveOne = function () { - total--; - if (total <= 0) { - if (hadError) { - promise.reject(errors); - } else { - promise.resolve.apply(promise, returnValue); - } - } - }; - - var chain = function (object, index) { - if (ParsePromise.is(object)) { - object.then(function (result) { - results[index] = result; - resolveOne(); - }, function (error) { - errors[index] = error; - hadError = true; - resolveOne(); - }); - } else { - results[i] = object; - resolveOne(); - } - }; - for (var i = 0; i < objects.length; i++) { - chain(objects[i], i); - } - - return promise; - } - - /** - * Returns a new promise that is fulfilled when all of the promises in the - * iterable argument are resolved. If any promise in the list fails, then - * the returned promise will be immediately rejected with the reason that - * single promise rejected. If they all succeed, then the returned promise - * will succeed, with the results being the results of all the input - * promises. If the iterable provided is empty, the returned promise will - * be immediately resolved. - * - * For example:
                          -     *   var p1 = Parse.Promise.as(1);
                          -     *   var p2 = Parse.Promise.as(2);
                          -     *   var p3 = Parse.Promise.as(3);
                          -     *
                          -     *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
                          -     *     console.log(r1);  // prints 1
                          -     *     console.log(r2);  // prints 2
                          -     *     console.log(r3);  // prints 3
                          -     *   });
                          - * - * @method all - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'all', - value: function (promises) { - var total = 0; - var objects = []; - - var _iteratorNormalCompletion = true; - var _didIteratorError = false; - var _iteratorError = undefined; - - try { - for (var _iterator = (0, _getIterator3.default)(promises), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { - var p = _step.value; - - objects[total++] = p; - } - } catch (err) { - _didIteratorError = true; - _iteratorError = err; - } finally { - try { - if (!_iteratorNormalCompletion && _iterator.return) { - _iterator.return(); - } - } finally { - if (_didIteratorError) { - throw _iteratorError; - } - } - } - - if (total === 0) { - return ParsePromise.as([]); - } - - var hadError = false; - var promise = new ParsePromise(); - var resolved = 0; - var results = []; - objects.forEach(function (object, i) { - if (ParsePromise.is(object)) { - object.then(function (result) { - if (hadError) { - return false; - } - results[i] = result; - resolved++; - if (resolved >= total) { - promise.resolve(results); - } - }, function (error) { - // Reject immediately - promise.reject(error); - hadError = true; - }); - } else { - results[i] = object; - resolved++; - if (!hadError && resolved >= total) { - promise.resolve(results); - } - } - }); - - return promise; - } - - /** - * Returns a new promise that is immediately fulfilled when any of the - * promises in the iterable argument are resolved or rejected. If the - * first promise to complete is resolved, the returned promise will be - * resolved with the same value. Likewise, if the first promise to - * complete is rejected, the returned promise will be rejected with the - * same reason. - * - * @method race - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - - }, { - key: 'race', - value: function (promises) { - var completed = false; - var promise = new ParsePromise(); - var _iteratorNormalCompletion2 = true; - var _didIteratorError2 = false; - var _iteratorError2 = undefined; - - try { - for (var _iterator2 = (0, _getIterator3.default)(promises), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { - var p = _step2.value; - - if (ParsePromise.is(p)) { - p.then(function (result) { - if (completed) { - return; - } - completed = true; - promise.resolve(result); - }, function (error) { - if (completed) { - return; - } - completed = true; - promise.reject(error); - }); - } else if (!completed) { - completed = true; - promise.resolve(p); - } - } - } catch (err) { - _didIteratorError2 = true; - _iteratorError2 = err; - } finally { - try { - if (!_iteratorNormalCompletion2 && _iterator2.return) { - _iterator2.return(); - } - } finally { - if (_didIteratorError2) { - throw _iteratorError2; - } - } - } - - return promise; - } - - /** - * Runs the given asyncFunction repeatedly, as long as the predicate - * function returns a truthy value. Stops repeating if asyncFunction returns - * a rejected promise. - * @method _continueWhile - * @param {Function} predicate should return false when ready to stop. - * @param {Function} asyncFunction should return a Promise. - * @static - */ - - }, { - key: '_continueWhile', - value: function (predicate, asyncFunction) { - if (predicate()) { - return asyncFunction().then(function () { - return ParsePromise._continueWhile(predicate, asyncFunction); - }); - } - return ParsePromise.as(); - } - }, { - key: 'isPromisesAPlusCompliant', - value: function () { - return _isPromisesAPlusCompliant; - } - }, { - key: 'enableAPlusCompliant', - value: function () { - _isPromisesAPlusCompliant = true; - } - }, { - key: 'disableAPlusCompliant', - value: function () { - _isPromisesAPlusCompliant = false; - } - }]); - return ParsePromise; -}(); - -exports.default = ParsePromise; \ No newline at end of file diff --git a/lib/node/ParseQuery.js b/lib/node/ParseQuery.js deleted file mode 100644 index 664f5a737..000000000 --- a/lib/node/ParseQuery.js +++ /dev/null @@ -1,1340 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _encode = require('./encode'); - -var _encode2 = _interopRequireDefault(_encode); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Converts a string into a regex that matches it. - * Surrounding with \Q .. \E does this, we just need to escape any \E's in - * the text separately. - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function quote(s) { - return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; -} - -/** - * Handles pre-populating the result data of a query with select fields, - * making sure that the data object contains keys for all objects that have - * been requested with a select, so that our cached state updates correctly. - */ -function handleSelectResult(data, select) { - var serverDataMask = {}; - - select.forEach(function (field) { - var hasSubObjectSelect = field.indexOf(".") !== -1; - if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { - // this field was selected, but is missing from the retrieved data - data[field] = undefined; - } else if (hasSubObjectSelect) { - // this field references a sub-object, - // so we need to walk down the path components - var pathComponents = field.split("."); - var obj = data; - var serverMask = serverDataMask; - - pathComponents.forEach(function (component, index, arr) { - // add keys if the expected data is missing - if (!obj[component]) { - obj[component] = index == arr.length - 1 ? undefined : {}; - } - obj = obj[component]; - - //add this path component to the server mask so we can fill it in later if needed - if (index < arr.length - 1) { - if (!serverMask[component]) { - serverMask[component] = {}; - } - } - }); - } - }); - - if ((0, _keys2.default)(serverDataMask).length > 0) { - var copyMissingDataWithMask = function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { - //copy missing elements at this level - if (copyThisLevel) { - for (var key in src) { - if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { - dest[key] = src[key]; - } - } - } - for (var key in mask) { - //traverse into objects as needed - copyMissingDataWithMask(src[key], dest[key], mask[key], true); - } - }; - - // When selecting from sub-objects, we don't want to blow away the missing - // information that we may have retrieved before. We've already added any - // missing selected keys to sub-objects, but we still need to add in the - // data for any previously retrieved sub-objects that were not selected. - - var serverData = _CoreManager2.default.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); - - copyMissingDataWithMask(serverData, data, serverDataMask, false); - } -} - -/** - * Creates a new parse Parse.Query for the given Parse.Object subclass. - * @class Parse.Query - * @constructor - * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. - * - *

                          Parse.Query defines a query that is used to fetch Parse.Objects. The - * most common use case is finding all objects that match a query through the - * find method. For example, this sample code fetches all objects - * of class MyClass. It calls a different function depending on - * whether the fetch succeeded or not. - * - *

                          - * var query = new Parse.Query(MyClass);
                          - * query.find({
                          - *   success: function(results) {
                          - *     // results is an array of Parse.Object.
                          - *   },
                          - *
                          - *   error: function(error) {
                          - *     // error is an instance of Parse.Error.
                          - *   }
                          - * });

                          - * - *

                          A Parse.Query can also be used to retrieve a single object whose id is - * known, through the get method. For example, this sample code fetches an - * object of class MyClass and id myId. It calls a - * different function depending on whether the fetch succeeded or not. - * - *

                          - * var query = new Parse.Query(MyClass);
                          - * query.get(myId, {
                          - *   success: function(object) {
                          - *     // object is an instance of Parse.Object.
                          - *   },
                          - *
                          - *   error: function(object, error) {
                          - *     // error is an instance of Parse.Error.
                          - *   }
                          - * });

                          - * - *

                          A Parse.Query can also be used to count the number of objects that match - * the query without retrieving all of those objects. For example, this - * sample code counts the number of objects of the class MyClass - *

                          - * var query = new Parse.Query(MyClass);
                          - * query.count({
                          - *   success: function(number) {
                          - *     // There are number instances of MyClass.
                          - *   },
                          - *
                          - *   error: function(error) {
                          - *     // error is an instance of Parse.Error.
                          - *   }
                          - * });

                          - */ - -var ParseQuery = function () { - function ParseQuery(objectClass) { - (0, _classCallCheck3.default)(this, ParseQuery); - - if (typeof objectClass === 'string') { - if (objectClass === 'User' && _CoreManager2.default.get('PERFORM_USER_REWRITE')) { - this.className = '_User'; - } else { - this.className = objectClass; - } - } else if (objectClass instanceof _ParseObject2.default) { - this.className = objectClass.className; - } else if (typeof objectClass === 'function') { - if (typeof objectClass.className === 'string') { - this.className = objectClass.className; - } else { - var obj = new objectClass(); - this.className = obj.className; - } - } else { - throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); - } - - this._where = {}; - this._include = []; - this._limit = -1; // negative limit is not sent in the server request - this._skip = 0; - this._extraOptions = {}; - } - - /** - * Adds constraint that at least one of the passed in queries matches. - * @method _orQuery - * @param {Array} queries - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - (0, _createClass3.default)(ParseQuery, [{ - key: '_orQuery', - value: function (queries) { - var queryJSON = queries.map(function (q) { - return q.toJSON().where; - }); - - this._where.$or = queryJSON; - return this; - } - - /** - * Helper for condition queries - */ - - }, { - key: '_addCondition', - value: function (key, condition, value) { - if (!this._where[key] || typeof this._where[key] === 'string') { - this._where[key] = {}; - } - this._where[key][condition] = (0, _encode2.default)(value, false, true); - return this; - } - - /** - * Converts string for regular expression at the beginning - */ - - }, { - key: '_regexStartWith', - value: function (string) { - return '^' + quote(string); - } - - /** - * Returns a JSON representation of this query. - * @method toJSON - * @return {Object} The JSON representation of the query. - */ - - }, { - key: 'toJSON', - value: function () { - var params = { - where: this._where - }; - - if (this._include.length) { - params.include = this._include.join(','); - } - if (this._select) { - params.keys = this._select.join(','); - } - if (this._limit >= 0) { - params.limit = this._limit; - } - if (this._skip > 0) { - params.skip = this._skip; - } - if (this._order) { - params.order = this._order.join(','); - } - for (var key in this._extraOptions) { - params[key] = this._extraOptions[key]; - } - - return params; - } - - /** - * Constructs a Parse.Object whose id is already known by fetching data from - * the server. Either options.success or options.error is called when the - * find completes. - * - * @method get - * @param {String} objectId The id of the object to be fetched. - * @param {Object} options A Backbone-style options object. - * Valid options are:
                            - *
                          • success: A Backbone-style success callback - *
                          • error: An Backbone-style error callback. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * - * @return {Parse.Promise} A promise that is resolved with the result when - * the query completes. - */ - - }, { - key: 'get', - value: function (objectId, options) { - this.equalTo('objectId', objectId); - - var firstOptions = {}; - if (options && options.hasOwnProperty('useMasterKey')) { - firstOptions.useMasterKey = options.useMasterKey; - } - if (options && options.hasOwnProperty('sessionToken')) { - firstOptions.sessionToken = options.sessionToken; - } - - return this.first(firstOptions).then(function (response) { - if (response) { - return response; - } - - var errorObject = new _ParseError2.default(_ParseError2.default.OBJECT_NOT_FOUND, 'Object not found.'); - return _ParsePromise2.default.error(errorObject); - })._thenRunCallbacks(options, null); - } - - /** - * Retrieves a list of ParseObjects that satisfy this query. - * Either options.success or options.error is called when the find - * completes. - * - * @method find - * @param {Object} options A Backbone-style options object. Valid options - * are:
                            - *
                          • success: Function to call when the find completes successfully. - *
                          • error: Function to call when the find fails. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * - * @return {Parse.Promise} A promise that is resolved with the results when - * the query completes. - */ - - }, { - key: 'find', - value: function (options) { - var _this2 = this; - - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var select = this._select; - - return controller.find(this.className, this.toJSON(), findOptions).then(function (response) { - return response.results.map(function (data) { - // In cases of relations, the server may send back a className - // on the top level of the payload - var override = response.className || _this2.className; - if (!data.className) { - data.className = override; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(data, select); - } - - return _ParseObject2.default.fromJSON(data, !select); - }); - })._thenRunCallbacks(options); - } - - /** - * Counts the number of objects that match this query. - * Either options.success or options.error is called when the count - * completes. - * - * @method count - * @param {Object} options A Backbone-style options object. Valid options - * are:
                            - *
                          • success: Function to call when the count completes successfully. - *
                          • error: Function to call when the find fails. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * - * @return {Parse.Promise} A promise that is resolved with the count when - * the query completes. - */ - - }, { - key: 'count', - value: function (options) { - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var params = this.toJSON(); - params.limit = 0; - params.count = 1; - - return controller.find(this.className, params, findOptions).then(function (result) { - return result.count; - })._thenRunCallbacks(options); - } - - /** - * Retrieves at most one Parse.Object that satisfies this query. - * - * Either options.success or options.error is called when it completes. - * success is passed the object if there is one. otherwise, undefined. - * - * @method first - * @param {Object} options A Backbone-style options object. Valid options - * are:
                            - *
                          • success: Function to call when the find completes successfully. - *
                          • error: Function to call when the find fails. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * - * @return {Parse.Promise} A promise that is resolved with the object when - * the query completes. - */ - - }, { - key: 'first', - value: function (options) { - var _this3 = this; - - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = _CoreManager2.default.getQueryController(); - - var params = this.toJSON(); - params.limit = 1; - - var select = this._select; - - return controller.find(this.className, params, findOptions).then(function (response) { - var objects = response.results; - if (!objects[0]) { - return undefined; - } - if (!objects[0].className) { - objects[0].className = _this3.className; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(objects[0], select); - } - - return _ParseObject2.default.fromJSON(objects[0], !select); - })._thenRunCallbacks(options); - } - - /** - * Iterates over each result of a query, calling a callback for each one. If - * the callback returns a promise, the iteration will not continue until - * that promise has been fulfilled. If the callback returns a rejected - * promise, then iteration will stop with that error. The items are - * processed in an unspecified order. The query may not have any sort order, - * and may not use limit or skip. - * @method each - * @param {Function} callback Callback that will be called with each result - * of the query. - * @param {Object} options A Backbone-style options object. Valid options - * are:
                            - *
                          • success: Function to call when the iteration completes successfully. - *
                          • error: Function to call when the iteration fails. - *
                          • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                          • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                          - * @return {Parse.Promise} A promise that will be fulfilled once the - * iteration has completed. - */ - - }, { - key: 'each', - value: function (callback, options) { - options = options || {}; - - if (this._order || this._skip || this._limit >= 0) { - return _ParsePromise2.default.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); - } - - new _ParsePromise2.default(); - - - var query = new ParseQuery(this.className); - // We can override the batch size from the options. - // This is undocumented, but useful for testing. - query._limit = options.batchSize || 100; - query._include = this._include.map(function (i) { - return i; - }); - if (this._select) { - query._select = this._select.map(function (s) { - return s; - }); - } - - query._where = {}; - for (var attr in this._where) { - var val = this._where[attr]; - if (Array.isArray(val)) { - query._where[attr] = val.map(function (v) { - return v; - }); - } else if (val && (typeof val === 'undefined' ? 'undefined' : (0, _typeof3.default)(val)) === 'object') { - var conditionMap = {}; - query._where[attr] = conditionMap; - for (var cond in val) { - conditionMap[cond] = val[cond]; - } - } else { - query._where[attr] = val; - } - } - - query.ascending('objectId'); - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var finished = false; - return _ParsePromise2.default._continueWhile(function () { - return !finished; - }, function () { - return query.find(findOptions).then(function (results) { - var callbacksDone = _ParsePromise2.default.as(); - results.forEach(function (result) { - callbacksDone = callbacksDone.then(function () { - return callback(result); - }); - }); - - return callbacksDone.then(function () { - if (results.length >= query._limit) { - query.greaterThan('objectId', results[results.length - 1].id); - } else { - finished = true; - } - }); - }); - })._thenRunCallbacks(options); - } - - /** Query Conditions **/ - - /** - * Adds a constraint to the query that requires a particular key's value to - * be equal to the provided value. - * @method equalTo - * @param {String} key The key to check. - * @param value The value that the Parse.Object must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'equalTo', - value: function (key, value) { - if (typeof value === 'undefined') { - return this.doesNotExist(key); - } - - this._where[key] = (0, _encode2.default)(value, false, true); - return this; - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be not equal to the provided value. - * @method notEqualTo - * @param {String} key The key to check. - * @param value The value that must not be equalled. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'notEqualTo', - value: function (key, value) { - return this._addCondition(key, '$ne', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than the provided value. - * @method lessThan - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'lessThan', - value: function (key, value) { - return this._addCondition(key, '$lt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than the provided value. - * @method greaterThan - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'greaterThan', - value: function (key, value) { - return this._addCondition(key, '$gt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than or equal to the provided value. - * @method lessThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'lessThanOrEqualTo', - value: function (key, value) { - return this._addCondition(key, '$lte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than or equal to the provided value. - * @method greaterThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'greaterThanOrEqualTo', - value: function (key, value) { - return this._addCondition(key, '$gte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be contained in the provided list of values. - * @method containedIn - * @param {String} key The key to check. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containedIn', - value: function (key, value) { - return this._addCondition(key, '$in', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * not be contained in the provided list of values. - * @method notContainedIn - * @param {String} key The key to check. - * @param {Array} values The values that will not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'notContainedIn', - value: function (key, value) { - return this._addCondition(key, '$nin', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values. - * @method containsAll - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containsAll', - value: function (key, values) { - return this._addCondition(key, '$all', values); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values starting with given strings. - * @method containsAllStartingWith - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The string values that will match as starting string. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'containsAllStartingWith', - value: function (key, values) { - var _this = this; - if (!Array.isArray(values)) { - values = [values]; - } - - values = values.map(function (value) { - return { "$regex": _this._regexStartWith(value) }; - }); - - return this.containsAll(key, values); - } - - /** - * Adds a constraint for finding objects that contain the given key. - * @method exists - * @param {String} key The key that should exist. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'exists', - value: function (key) { - return this._addCondition(key, '$exists', true); - } - - /** - * Adds a constraint for finding objects that do not contain a given key. - * @method doesNotExist - * @param {String} key The key that should not exist - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotExist', - value: function (key) { - return this._addCondition(key, '$exists', false); - } - - /** - * Adds a regular expression constraint for finding string values that match - * the provided regular expression. - * This may be slow for large datasets. - * @method matches - * @param {String} key The key that the string to match is stored in. - * @param {RegExp} regex The regular expression pattern to match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matches', - value: function (key, regex, modifiers) { - this._addCondition(key, '$regex', regex); - if (!modifiers) { - modifiers = ''; - } - if (regex.ignoreCase) { - modifiers += 'i'; - } - if (regex.multiline) { - modifiers += 'm'; - } - if (modifiers.length) { - this._addCondition(key, '$options', modifiers); - } - return this; - } - - /** - * Adds a constraint that requires that a key's value matches a Parse.Query - * constraint. - * @method matchesQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matchesQuery', - value: function (key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$inQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value not matches a - * Parse.Query constraint. - * @method doesNotMatchQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotMatchQuery', - value: function (key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$notInQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value matches a value in - * an object returned by a different Parse.Query. - * @method matchesKeyInQuery - * @param {String} key The key that contains the value that is being - * matched. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'matchesKeyInQuery', - value: function (key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$select', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint that requires that a key's value not match a value in - * an object returned by a different Parse.Query. - * @method doesNotMatchKeyInQuery - * @param {String} key The key that contains the value that is being - * excluded. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'doesNotMatchKeyInQuery', - value: function (key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$dontSelect', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint for finding string values that contain a provided - * string. This may be slow for large datasets. - * @method contains - * @param {String} key The key that the string to match is stored in. - * @param {String} substring The substring that the value must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'contains', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value)); - } - - /** - * Adds a constraint for finding string values that start with a provided - * string. This query will use the backend index, so it will be fast even - * for large datasets. - * @method startsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} prefix The substring that the value must start with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'startsWith', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', this._regexStartWith(value)); - } - - /** - * Adds a constraint for finding string values that end with a provided - * string. This will be slow for large datasets. - * @method endsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} suffix The substring that the value must end with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'endsWith', - value: function (key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value) + '$'); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given. - * @method near - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'near', - value: function (key, point) { - if (!(point instanceof _ParseGeoPoint2.default)) { - // Try to cast it as a GeoPoint - point = new _ParseGeoPoint2.default(point); - } - return this._addCondition(key, '$nearSphere', point); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * @method withinRadians - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in radians) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinRadians', - value: function (key, point, distance) { - this.near(key, point); - return this._addCondition(key, '$maxDistance', distance); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 3958.8 miles. - * @method withinMiles - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in miles) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinMiles', - value: function (key, point, distance) { - return this.withinRadians(key, point, distance / 3958.8); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 6371.0 kilometers. - * @method withinKilometers - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in kilometers) of results - * to return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinKilometers', - value: function (key, point, distance) { - return this.withinRadians(key, point, distance / 6371.0); - } - - /** - * Adds a constraint to the query that requires a particular key's - * coordinates be contained within a given rectangular geographic bounding - * box. - * @method withinGeoBox - * @param {String} key The key to be constrained. - * @param {Parse.GeoPoint} southwest - * The lower-left inclusive corner of the box. - * @param {Parse.GeoPoint} northeast - * The upper-right inclusive corner of the box. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'withinGeoBox', - value: function (key, southwest, northeast) { - if (!(southwest instanceof _ParseGeoPoint2.default)) { - southwest = new _ParseGeoPoint2.default(southwest); - } - if (!(northeast instanceof _ParseGeoPoint2.default)) { - northeast = new _ParseGeoPoint2.default(northeast); - } - this._addCondition(key, '$within', { '$box': [southwest, northeast] }); - return this; - } - - /** Query Orderings **/ - - /** - * Sorts the results in ascending order by the given key. - * - * @method ascending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'ascending', - value: function () { - this._order = []; - - for (var _len = arguments.length, keys = Array(_len), _key = 0; _key < _len; _key++) { - keys[_key] = arguments[_key]; - } - - return this.addAscending.apply(this, keys); - } - - /** - * Sorts the results in ascending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addAscending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'addAscending', - value: function () { - var _this4 = this; - - if (!this._order) { - this._order = []; - } - - for (var _len2 = arguments.length, keys = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - keys[_key2] = arguments[_key2]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - key = key.join(); - } - _this4._order = _this4._order.concat(key.replace(/\s/g, '').split(',')); - }); - - return this; - } - - /** - * Sorts the results in descending order by the given key. - * - * @method descending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'descending', - value: function () { - this._order = []; - - for (var _len3 = arguments.length, keys = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - keys[_key3] = arguments[_key3]; - } - - return this.addDescending.apply(this, keys); - } - - /** - * Sorts the results in descending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addDescending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'addDescending', - value: function () { - var _this5 = this; - - if (!this._order) { - this._order = []; - } - - for (var _len4 = arguments.length, keys = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { - keys[_key4] = arguments[_key4]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - key = key.join(); - } - _this5._order = _this5._order.concat(key.replace(/\s/g, '').split(',').map(function (k) { - return '-' + k; - })); - }); - - return this; - } - - /** Query Options **/ - - /** - * Sets the number of results to skip before returning any results. - * This is useful for pagination. - * Default is to skip zero results. - * @method skip - * @param {Number} n the number of results to skip. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'skip', - value: function (n) { - if (typeof n !== 'number' || n < 0) { - throw new Error('You can only skip by a positive number'); - } - this._skip = n; - return this; - } - - /** - * Sets the limit of the number of results to return. The default limit is - * 100, with a maximum of 1000 results being returned at a time. - * @method limit - * @param {Number} n the number of results to limit to. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'limit', - value: function (n) { - if (typeof n !== 'number') { - throw new Error('You can only set the limit to a numeric value'); - } - this._limit = n; - return this; - } - - /** - * Includes nested Parse.Objects for the provided key. You can use dot - * notation to specify which fields in the included object are also fetched. - * @method include - * @param {String} key The name of the key to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'include', - value: function () { - var _this6 = this; - - for (var _len5 = arguments.length, keys = Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { - keys[_key5] = arguments[_key5]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - _this6._include = _this6._include.concat(key); - } else { - _this6._include.push(key); - } - }); - return this; - } - - /** - * Restricts the fields of the returned Parse.Objects to include only the - * provided keys. If this is called multiple times, then all of the keys - * specified in each of the calls will be included. - * @method select - * @param {Array} keys The names of the keys to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - - }, { - key: 'select', - value: function () { - var _this7 = this; - - if (!this._select) { - this._select = []; - } - - for (var _len6 = arguments.length, keys = Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { - keys[_key6] = arguments[_key6]; - } - - keys.forEach(function (key) { - if (Array.isArray(key)) { - _this7._select = _this7._select.concat(key); - } else { - _this7._select.push(key); - } - }); - return this; - } - - /** - * Subscribe this query to get liveQuery updates - * @method subscribe - * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter - * which can be used to get liveQuery updates. - */ - - }, { - key: 'subscribe', - value: function () { - var controller = _CoreManager2.default.getLiveQueryController(); - return controller.subscribe(this); - } - - /** - * Constructs a Parse.Query that is the OR of the passed in queries. For - * example: - *
                          var compoundQuery = Parse.Query.or(query1, query2, query3);
                          - * - * will create a compoundQuery that is an or of the query1, query2, and - * query3. - * @method or - * @param {...Parse.Query} var_args The list of queries to OR. - * @static - * @return {Parse.Query} The query that is the OR of the passed in queries. - */ - - }], [{ - key: 'or', - value: function () { - var className = null; - - for (var _len7 = arguments.length, queries = Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { - queries[_key7] = arguments[_key7]; - } - - queries.forEach(function (q) { - if (!className) { - className = q.className; - } - - if (className !== q.className) { - throw new Error('All queries must be for the same class.'); - } - }); - - var query = new ParseQuery(className); - query._orQuery(queries); - return query; - } - }]); - return ParseQuery; -}(); - -exports.default = ParseQuery; - -var DefaultController = { - find: function (className, params, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - return RESTController.request('GET', 'classes/' + className, params, options); - } -}; - -_CoreManager2.default.setQueryController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseRelation.js b/lib/node/ParseRelation.js deleted file mode 100644 index fe9ea8769..000000000 --- a/lib/node/ParseRelation.js +++ /dev/null @@ -1,182 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParseOp = require('./ParseOp'); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseQuery = require('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Creates a new Relation for the given parent object and key. This - * constructor should rarely be used directly, but rather created by - * Parse.Object.relation. - * @class Parse.Relation - * @constructor - * @param {Parse.Object} parent The parent of this relation. - * @param {String} key The key for this relation on the parent. - * - *

                          - * A class that is used to access all of the children of a many-to-many - * relationship. Each instance of Parse.Relation is associated with a - * particular parent object and key. - *

                          - */ -var ParseRelation = function () { - function ParseRelation(parent, key) { - (0, _classCallCheck3.default)(this, ParseRelation); - - this.parent = parent; - this.key = key; - this.targetClassName = null; - } - - /** - * Makes sure that this relation has the right parent and key. - */ - - (0, _createClass3.default)(ParseRelation, [{ - key: '_ensureParentAndKey', - value: function (parent, key) { - this.key = this.key || key; - if (this.key !== key) { - throw new Error('Internal Error. Relation retrieved from two different keys.'); - } - if (this.parent) { - if (this.parent.className !== parent.className) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - if (this.parent.id) { - if (this.parent.id !== parent.id) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - } else if (parent.id) { - this.parent = parent; - } - } else { - this.parent = parent; - } - } - - /** - * Adds a Parse.Object or an array of Parse.Objects to the relation. - * @method add - * @param {} objects The item or items to add. - */ - - }, { - key: 'add', - value: function (objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new _ParseOp.RelationOp(objects, []); - var parent = this.parent; - if (!parent) { - throw new Error('Cannot add to a Relation without a parent'); - } - parent.set(this.key, change); - this.targetClassName = change._targetClassName; - return parent; - } - - /** - * Removes a Parse.Object or an array of Parse.Objects from this relation. - * @method remove - * @param {} objects The item or items to remove. - */ - - }, { - key: 'remove', - value: function (objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new _ParseOp.RelationOp([], objects); - if (!this.parent) { - throw new Error('Cannot remove from a Relation without a parent'); - } - this.parent.set(this.key, change); - this.targetClassName = change._targetClassName; - } - - /** - * Returns a JSON version of the object suitable for saving to disk. - * @method toJSON - * @return {Object} - */ - - }, { - key: 'toJSON', - value: function () { - return { - __type: 'Relation', - className: this.targetClassName - }; - } - - /** - * Returns a Parse.Query that is limited to objects in this - * relation. - * @method query - * @return {Parse.Query} - */ - - }, { - key: 'query', - value: function () { - var query; - var parent = this.parent; - if (!parent) { - throw new Error('Cannot construct a query for a Relation without a parent'); - } - if (!this.targetClassName) { - query = new _ParseQuery2.default(parent.className); - query._extraOptions.redirectClassNameForKey = this.key; - } else { - query = new _ParseQuery2.default(this.targetClassName); - } - query._addCondition('$relatedTo', 'object', { - __type: 'Pointer', - className: parent.className, - objectId: parent.id - }); - query._addCondition('$relatedTo', 'key', this.key); - - return query; - } - }]); - return ParseRelation; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseRelation; \ No newline at end of file diff --git a/lib/node/ParseRole.js b/lib/node/ParseRole.js deleted file mode 100644 index 567af7a54..000000000 --- a/lib/node/ParseRole.js +++ /dev/null @@ -1,196 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _get2 = require('babel-runtime/helpers/get'); - -var _get3 = _interopRequireDefault(_get2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Represents a Role on the Parse server. Roles represent groupings of - * Users for the purposes of granting permissions (e.g. specifying an ACL - * for an Object). Roles are specified by their sets of child users and - * child roles, all of which are granted any permissions that the parent - * role has. - * - *

                          Roles must have a name (which cannot be changed after creation of the - * role), and must specify an ACL.

                          - * @class Parse.Role - * @constructor - * @param {String} name The name of the Role to create. - * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. - * A Parse.Role is a local representation of a role persisted to the Parse - * cloud. - */ -var ParseRole = function (_ParseObject) { - (0, _inherits3.default)(ParseRole, _ParseObject); - - function ParseRole(name, acl) { - (0, _classCallCheck3.default)(this, ParseRole); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseRole.__proto__ || (0, _getPrototypeOf2.default)(ParseRole)).call(this, '_Role')); - - if (typeof name === 'string' && acl instanceof _ParseACL2.default) { - _this.setName(name); - _this.setACL(acl); - } - return _this; - } - - /** - * Gets the name of the role. You can alternatively call role.get("name") - * - * @method getName - * @return {String} the name of the role. - */ - - (0, _createClass3.default)(ParseRole, [{ - key: 'getName', - value: function () { - var name = this.get('name'); - if (name == null || typeof name === 'string') { - return name; - } - return ''; - } - - /** - * Sets the name for a role. This value must be set before the role has - * been saved to the server, and cannot be set once the role has been - * saved. - * - *

                          - * A role's name can only contain alphanumeric characters, _, -, and - * spaces. - *

                          - * - *

                          This is equivalent to calling role.set("name", name)

                          - * - * @method setName - * @param {String} name The name of the role. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - - }, { - key: 'setName', - value: function (name, options) { - return this.set('name', name, options); - } - - /** - * Gets the Parse.Relation for the Parse.Users that are direct - * children of this role. These users are granted any privileges that this - * role has been granted (e.g. read or write access through ACLs). You can - * add or remove users from the role through this relation. - * - *

                          This is equivalent to calling role.relation("users")

                          - * - * @method getUsers - * @return {Parse.Relation} the relation for the users belonging to this - * role. - */ - - }, { - key: 'getUsers', - value: function () { - return this.relation('users'); - } - - /** - * Gets the Parse.Relation for the Parse.Roles that are direct - * children of this role. These roles' users are granted any privileges that - * this role has been granted (e.g. read or write access through ACLs). You - * can add or remove child roles from this role through this relation. - * - *

                          This is equivalent to calling role.relation("roles")

                          - * - * @method getRoles - * @return {Parse.Relation} the relation for the roles belonging to this - * role. - */ - - }, { - key: 'getRoles', - value: function () { - return this.relation('roles'); - } - }, { - key: 'validate', - value: function (attrs, options) { - var isInvalid = (0, _get3.default)(ParseRole.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseRole.prototype), 'validate', this).call(this, attrs, options); - if (isInvalid) { - return isInvalid; - } - - if ('name' in attrs && attrs.name !== this.getName()) { - var newName = attrs.name; - if (this.id && this.id !== attrs.objectId) { - // Check to see if the objectId being set matches this.id - // This happens during a fetch -- the id is set before calling fetch - // Let the name be set in this case - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); - } - if (typeof newName !== 'string') { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name must be a String.'); - } - if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { - return new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); - } - } - return false; - } - }]); - return ParseRole; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseRole; - -_ParseObject3.default.registerSubclass('_Role', ParseRole); \ No newline at end of file diff --git a/lib/node/ParseSession.js b/lib/node/ParseSession.js deleted file mode 100644 index 7fb75c80d..000000000 --- a/lib/node/ParseSession.js +++ /dev/null @@ -1,180 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _isRevocableSession = require('./isRevocableSession'); - -var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseUser = require('./ParseUser'); - -var _ParseUser2 = _interopRequireDefault(_ParseUser); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * @class Parse.Session - * @constructor - * - *

                          A Parse.Session object is a local representation of a revocable session. - * This class is a subclass of a Parse.Object, and retains the same - * functionality of a Parse.Object.

                          - */ -var ParseSession = function (_ParseObject) { - (0, _inherits3.default)(ParseSession, _ParseObject); - - function ParseSession(attributes) { - (0, _classCallCheck3.default)(this, ParseSession); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseSession.__proto__ || (0, _getPrototypeOf2.default)(ParseSession)).call(this, '_Session')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - return _this; - } - - /** - * Returns the session token string. - * @method getSessionToken - * @return {String} - */ - - (0, _createClass3.default)(ParseSession, [{ - key: 'getSessionToken', - value: function () { - var token = this.get('sessionToken'); - if (typeof token === 'string') { - return token; - } - return ''; - } - }], [{ - key: 'readOnlyAttributes', - value: function () { - return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; - } - - /** - * Retrieves the Session object for the currently logged in session. - * @method current - * @static - * @return {Parse.Promise} A promise that is resolved with the Parse.Session - * object after it has been fetched. If there is no current user, the - * promise will be rejected. - */ - - }, { - key: 'current', - value: function (options) { - options = options || {}; - var controller = _CoreManager2.default.getSessionController(); - - var sessionOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - sessionOptions.useMasterKey = options.useMasterKey; - } - return _ParseUser2.default.currentAsync().then(function (user) { - if (!user) { - return _ParsePromise2.default.error('There is no current user.'); - } - user.getSessionToken(); - - sessionOptions.sessionToken = user.getSessionToken(); - return controller.getSession(sessionOptions); - }); - } - - /** - * Determines whether the current session token is revocable. - * This method is useful for migrating Express.js or Node.js web apps to - * use revocable sessions. If you are migrating an app that uses the Parse - * SDK in the browser only, please use Parse.User.enableRevocableSession() - * instead, so that sessions can be automatically upgraded. - * @method isCurrentSessionRevocable - * @static - * @return {Boolean} - */ - - }, { - key: 'isCurrentSessionRevocable', - value: function () { - var currentUser = _ParseUser2.default.current(); - if (currentUser) { - return (0, _isRevocableSession2.default)(currentUser.getSessionToken() || ''); - } - return false; - } - }]); - return ParseSession; -}(_ParseObject3.default); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -exports.default = ParseSession; - -_ParseObject3.default.registerSubclass('_Session', ParseSession); - -var DefaultController = { - getSession: function (options) { - var RESTController = _CoreManager2.default.getRESTController(); - var session = new ParseSession(); - - return RESTController.request('GET', 'sessions/me', {}, options).then(function (sessionData) { - session._finishFetch(sessionData); - session._setExisted(true); - return session; - }); - } -}; - -_CoreManager2.default.setSessionController(DefaultController); \ No newline at end of file diff --git a/lib/node/ParseUser.js b/lib/node/ParseUser.js deleted file mode 100644 index f18f42820..000000000 --- a/lib/node/ParseUser.js +++ /dev/null @@ -1,1150 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _defineProperty = require('babel-runtime/core-js/object/define-property'); - -var _defineProperty2 = _interopRequireDefault(_defineProperty); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _getPrototypeOf = require('babel-runtime/core-js/object/get-prototype-of'); - -var _getPrototypeOf2 = _interopRequireDefault(_getPrototypeOf); - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); - -var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); - -var _get2 = require('babel-runtime/helpers/get'); - -var _get3 = _interopRequireDefault(_get2); - -var _inherits2 = require('babel-runtime/helpers/inherits'); - -var _inherits3 = _interopRequireDefault(_inherits2); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _isRevocableSession = require('./isRevocableSession'); - -var _isRevocableSession2 = _interopRequireDefault(_isRevocableSession); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParseObject2 = require('./ParseObject'); - -var _ParseObject3 = _interopRequireDefault(_ParseObject2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _ParseSession = require('./ParseSession'); - -var _ParseSession2 = _interopRequireDefault(_ParseSession); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var CURRENT_USER_KEY = 'currentUser'; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var canUseCurrentUser = !_CoreManager2.default.get('IS_NODE'); -var currentUserCacheMatchesDisk = false; -var currentUserCache = null; - -var authProviders = {}; - -/** - * @class Parse.User - * @constructor - * - *

                          A Parse.User object is a local representation of a user persisted to the - * Parse cloud. This class is a subclass of a Parse.Object, and retains the - * same functionality of a Parse.Object, but also extends it with various - * user specific methods, like authentication, signing up, and validation of - * uniqueness.

                          - */ - -var ParseUser = function (_ParseObject) { - (0, _inherits3.default)(ParseUser, _ParseObject); - - function ParseUser(attributes) { - (0, _classCallCheck3.default)(this, ParseUser); - - var _this = (0, _possibleConstructorReturn3.default)(this, (ParseUser.__proto__ || (0, _getPrototypeOf2.default)(ParseUser)).call(this, '_User')); - - if (attributes && (typeof attributes === 'undefined' ? 'undefined' : (0, _typeof3.default)(attributes)) === 'object') { - if (!_this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Parse User'); - } - } - return _this; - } - - /** - * Request a revocable session token to replace the older style of token. - * @method _upgradeToRevocableSession - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is resolved when the replacement - * token has been fetched. - */ - - (0, _createClass3.default)(ParseUser, [{ - key: '_upgradeToRevocableSession', - value: function (options) { - options = options || {}; - - var upgradeOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - upgradeOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); - } - - /** - * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can - * call linkWith on the user (even if it doesn't exist yet on the server). - * @method _linkWith - */ - - }, { - key: '_linkWith', - value: function (provider, options) { - var _this2 = this; - - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[provider]; - } else { - authType = provider.getAuthType(); - } - if (options && options.hasOwnProperty('authData')) { - var authData = this.get('authData') || {}; - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - throw new Error('Invalid type: authData field should be an object'); - } - authData[authType] = options.authData; - - var controller = _CoreManager2.default.getUserController(); - return controller.linkWith(this, authData)._thenRunCallbacks(options, this); - } else { - var promise = new _ParsePromise2.default(); - provider.authenticate({ - success: function (provider, result) { - var opts = {}; - opts.authData = result; - if (options.success) { - opts.success = options.success; - } - if (options.error) { - opts.error = options.error; - } - _this2._linkWith(provider, opts).then(function () { - promise.resolve(_this2); - }, function (error) { - promise.reject(error); - }); - }, - error: function (provider, _error) { - if (typeof options.error === 'function') { - options.error(_this2, _error); - } - promise.reject(_error); - } - }); - return promise; - } - } - - /** - * Synchronizes auth data for a provider (e.g. puts the access token in the - * right place to be used by the Facebook SDK). - * @method _synchronizeAuthData - */ - - }, { - key: '_synchronizeAuthData', - value: function (provider) { - if (!this.isCurrent() || !provider) { - return; - } - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[authType]; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData'); - if (!provider || !authData || (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - var success = provider.restoreAuthentication(authData[authType]); - if (!success) { - this._unlinkFrom(provider); - } - } - - /** - * Synchronizes authData for all providers. - * @method _synchronizeAllAuthData - */ - - }, { - key: '_synchronizeAllAuthData', - value: function () { - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - this._synchronizeAuthData(key); - } - } - - /** - * Removes null values from authData (which exist temporarily for - * unlinking) - * @method _cleanupAuthData - */ - - }, { - key: '_cleanupAuthData', - value: function () { - if (!this.isCurrent()) { - return; - } - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - if (!authData[key]) { - delete authData[key]; - } - } - } - - /** - * Unlinks a user from a service. - * @method _unlinkFrom - */ - - }, { - key: '_unlinkFrom', - value: function (provider, options) { - var _this3 = this; - - if (typeof provider === 'string') { - provider = authProviders[provider]; - } else { - provider.getAuthType(); - } - return this._linkWith(provider, { authData: null }).then(function () { - _this3._synchronizeAuthData(provider); - return _ParsePromise2.default.as(_this3); - })._thenRunCallbacks(options); - } - - /** - * Checks whether a user is linked to a service. - * @method _isLinked - */ - - }, { - key: '_isLinked', - value: function (provider) { - var authType; - if (typeof provider === 'string') { - authType = provider; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData') || {}; - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return false; - } - return !!authData[authType]; - } - - /** - * Deauthenticates all providers. - * @method _logOutWithAll - */ - - }, { - key: '_logOutWithAll', - value: function () { - var authData = this.get('authData'); - if ((typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) !== 'object') { - return; - } - - for (var key in authData) { - this._logOutWith(key); - } - } - - /** - * Deauthenticates a single provider (e.g. removing access tokens from the - * Facebook SDK). - * @method _logOutWith - */ - - }, { - key: '_logOutWith', - value: function (provider) { - if (!this.isCurrent()) { - return; - } - if (typeof provider === 'string') { - provider = authProviders[provider]; - } - if (provider && provider.deauthenticate) { - provider.deauthenticate(); - } - } - - /** - * Class instance method used to maintain specific keys when a fetch occurs. - * Used to ensure that the session token is not lost. - */ - - }, { - key: '_preserveFieldsOnFetch', - value: function () { - return { - sessionToken: this.get('sessionToken') - }; - } - - /** - * Returns true if current would return this user. - * @method isCurrent - * @return {Boolean} - */ - - }, { - key: 'isCurrent', - value: function () { - var current = ParseUser.current(); - return !!current && current.id === this.id; - } - - /** - * Returns get("username"). - * @method getUsername - * @return {String} - */ - - }, { - key: 'getUsername', - value: function () { - var username = this.get('username'); - if (username == null || typeof username === 'string') { - return username; - } - return ''; - } - - /** - * Calls set("username", username, options) and returns the result. - * @method setUsername - * @param {String} username - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setUsername', - value: function (username) { - // Strip anonymity, even we do not support anonymous user in js SDK, we may - // encounter anonymous user created by android/iOS in cloud code. - var authData = this.get('authData'); - if (authData && (typeof authData === 'undefined' ? 'undefined' : (0, _typeof3.default)(authData)) === 'object' && authData.hasOwnProperty('anonymous')) { - // We need to set anonymous to null instead of deleting it in order to remove it from Parse. - authData.anonymous = null; - } - this.set('username', username); - } - - /** - * Calls set("password", password, options) and returns the result. - * @method setPassword - * @param {String} password - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setPassword', - value: function (password) { - this.set('password', password); - } - - /** - * Returns get("email"). - * @method getEmail - * @return {String} - */ - - }, { - key: 'getEmail', - value: function () { - var email = this.get('email'); - if (email == null || typeof email === 'string') { - return email; - } - return ''; - } - - /** - * Calls set("email", email, options) and returns the result. - * @method setEmail - * @param {String} email - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - - }, { - key: 'setEmail', - value: function (email) { - this.set('email', email); - } - - /** - * Returns the session token for this user, if the user has been logged in, - * or if it is the result of a query with the master key. Otherwise, returns - * undefined. - * @method getSessionToken - * @return {String} the session token, or undefined - */ - - }, { - key: 'getSessionToken', - value: function () { - var token = this.get('sessionToken'); - if (token == null || typeof token === 'string') { - return token; - } - return ''; - } - - /** - * Checks whether this user is the current user and has been authenticated. - * @method authenticated - * @return (Boolean) whether this user is the current user and is logged in. - */ - - }, { - key: 'authenticated', - value: function () { - var current = ParseUser.current(); - return !!this.get('sessionToken') && !!current && current.id === this.id; - } - - /** - * Signs up a new user. You should call this instead of save for - * new Parse.Users. This will create a new Parse.User on the server, and - * also persist the session on disk so that you can access the user using - * current. - * - *

                          A username and password must be set before calling signUp.

                          - * - *

                          Calls options.success or options.error on completion.

                          - * - * @method signUp - * @param {Object} attrs Extra fields to set on the new user, or null. - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled when the signup - * finishes. - */ - - }, { - key: 'signUp', - value: function (attrs, options) { - options = options || {}; - - var signupOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - signupOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - signupOptions.installationId = options.installationId; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); - } - - /** - * Logs in a Parse.User. On success, this saves the session to disk, - * so you can retrieve the currently logged in user using - * current. - * - *

                          A username and password must be set before calling logIn.

                          - * - *

                          Calls options.success or options.error on completion.

                          - * - * @method logIn - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login is complete. - */ - - }, { - key: 'logIn', - value: function (options) { - options = options || {}; - - var loginOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - loginOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - loginOptions.installationId = options.installationId; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); - } - - /** - * Wrap the default save behavior with functionality to save to local - * storage if this is current user. - */ - - }, { - key: 'save', - value: function () { - var _this4 = this; - - for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { - args[_key] = arguments[_key]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'save', this).apply(this, args).then(function () { - if (_this4.isCurrent()) { - return _CoreManager2.default.getUserController().updateUserOnDisk(_this4); - } - return _this4; - }); - } - - /** - * Wrap the default destroy behavior with functionality that logs out - * the current user when it is destroyed - */ - - }, { - key: 'destroy', - value: function () { - var _this5 = this; - - for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { - args[_key2] = arguments[_key2]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'destroy', this).apply(this, args).then(function () { - if (_this5.isCurrent()) { - return _CoreManager2.default.getUserController().removeUserFromDisk(); - } - return _this5; - }); - } - - /** - * Wrap the default fetch behavior with functionality to save to local - * storage if this is current user. - */ - - }, { - key: 'fetch', - value: function () { - var _this6 = this; - - for (var _len3 = arguments.length, args = Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { - args[_key3] = arguments[_key3]; - } - - return (0, _get3.default)(ParseUser.prototype.__proto__ || (0, _getPrototypeOf2.default)(ParseUser.prototype), 'fetch', this).apply(this, args).then(function () { - if (_this6.isCurrent()) { - return _CoreManager2.default.getUserController().updateUserOnDisk(_this6); - } - return _this6; - }); - } - }], [{ - key: 'readOnlyAttributes', - value: function () { - return ['sessionToken']; - } - - /** - * Adds functionality to the existing Parse.User class - * @method extend - * @param {Object} protoProps A set of properties to add to the prototype - * @param {Object} classProps A set of static properties to add to the class - * @static - * @return {Class} The newly extended Parse.User class - */ - - }, { - key: 'extend', - value: function (protoProps, classProps) { - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseUser.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - (0, _defineProperty2.default)(ParseUser, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - return ParseUser; - } - - /** - * Retrieves the currently logged in ParseUser with a valid session, - * either from memory or localStorage, if necessary. - * @method current - * @static - * @return {Parse.Object} The currently logged in Parse.User. - */ - - }, { - key: 'current', - value: function () { - if (!canUseCurrentUser) { - return null; - } - var controller = _CoreManager2.default.getUserController(); - return controller.currentUser(); - } - - /** - * Retrieves the currently logged in ParseUser from asynchronous Storage. - * @method currentAsync - * @static - * @return {Parse.Promise} A Promise that is resolved with the currently - * logged in Parse User - */ - - }, { - key: 'currentAsync', - value: function () { - if (!canUseCurrentUser) { - return _ParsePromise2.default.as(null); - } - var controller = _CoreManager2.default.getUserController(); - return controller.currentUserAsync(); - } - - /** - * Signs up a new user with a username (or email) and password. - * This will create a new Parse.User on the server, and also persist the - * session in localStorage so that you can access the user using - * {@link #current}. - * - *

                          Calls options.success or options.error on completion.

                          - * - * @method signUp - * @param {String} username The username (or email) to sign up with. - * @param {String} password The password to sign up with. - * @param {Object} attrs Extra fields to set on the new user. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the signup completes. - */ - - }, { - key: 'signUp', - value: function (username, password, attrs, options) { - attrs = attrs || {}; - attrs.username = username; - attrs.password = password; - var user = new ParseUser(attrs); - return user.signUp({}, options); - } - - /** - * Logs in a user with a username (or email) and password. On success, this - * saves the session to disk, so you can retrieve the currently logged in - * user using current. - * - *

                          Calls options.success or options.error on completion.

                          - * - * @method logIn - * @param {String} username The username (or email) to log in with. - * @param {String} password The password to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - - }, { - key: 'logIn', - value: function (username, password, options) { - if (typeof username !== 'string') { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Username must be a string.')); - } else if (typeof password !== 'string') { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Password must be a string.')); - } - var user = new ParseUser(); - user._finishFetch({ username: username, password: password }); - return user.logIn(options); - } - - /** - * Logs in a user with a session token. On success, this saves the session - * to disk, so you can retrieve the currently logged in user using - * current. - * - *

                          Calls options.success or options.error on completion.

                          - * - * @method become - * @param {String} sessionToken The sessionToken to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - - }, { - key: 'become', - value: function (sessionToken, options) { - if (!canUseCurrentUser) { - throw new Error('It is not memory-safe to become a user in a server environment'); - } - options = options || {}; - - var becomeOptions = { - sessionToken: sessionToken - }; - if (options.hasOwnProperty('useMasterKey')) { - becomeOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.become(becomeOptions)._thenRunCallbacks(options); - } - }, { - key: 'logInWith', - value: function (provider, options) { - return ParseUser._logInWith(provider, options); - } - - /** - * Logs out the currently logged in user session. This will remove the - * session from disk, log out of linked services, and future calls to - * current will return null. - * @method logOut - * @static - * @return {Parse.Promise} A promise that is resolved when the session is - * destroyed on the server. - */ - - }, { - key: 'logOut', - value: function () { - if (!canUseCurrentUser) { - throw new Error('There is no current user user on a node.js server environment.'); - } - - var controller = _CoreManager2.default.getUserController(); - return controller.logOut(); - } - - /** - * Requests a password reset email to be sent to the specified email address - * associated with the user account. This email allows the user to securely - * reset their password on the Parse site. - * - *

                          Calls options.success or options.error on completion.

                          - * - * @method requestPasswordReset - * @param {String} email The email address associated with the user that - * forgot their password. - * @param {Object} options A Backbone-style options object. - * @static - */ - - }, { - key: 'requestPasswordReset', - value: function (email, options) { - options = options || {}; - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - - var controller = _CoreManager2.default.getUserController(); - return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); - } - - /** - * Allow someone to define a custom User class without className - * being rewritten to _User. The default behavior is to rewrite - * User to _User for legacy reasons. This allows developers to - * override that behavior. - * - * @method allowCustomUserClass - * @param {Boolean} isAllowed Whether or not to allow custom User class - * @static - */ - - }, { - key: 'allowCustomUserClass', - value: function (isAllowed) { - _CoreManager2.default.set('PERFORM_USER_REWRITE', !isAllowed); - } - - /** - * Allows a legacy application to start using revocable sessions. If the - * current session token is not revocable, a request will be made for a new, - * revocable session. - * It is not necessary to call this method from cloud code unless you are - * handling user signup or login from the server side. In a cloud code call, - * this function will not attempt to upgrade the current token. - * @method enableRevocableSession - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is resolved when the process has - * completed. If a replacement session token is requested, the promise - * will be resolved after a new token has been fetched. - */ - - }, { - key: 'enableRevocableSession', - value: function (options) { - options = options || {}; - _CoreManager2.default.set('FORCE_REVOCABLE_SESSION', true); - if (canUseCurrentUser) { - var current = ParseUser.current(); - if (current) { - return current._upgradeToRevocableSession(options); - } - } - return _ParsePromise2.default.as()._thenRunCallbacks(options); - } - - /** - * Enables the use of become or the current user in a server - * environment. These features are disabled by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method enableUnsafeCurrentUser - * @static - */ - - }, { - key: 'enableUnsafeCurrentUser', - value: function () { - canUseCurrentUser = true; - } - - /** - * Disables the use of become or the current user in any environment. - * These features are disabled on servers by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method disableUnsafeCurrentUser - * @static - */ - - }, { - key: 'disableUnsafeCurrentUser', - value: function () { - canUseCurrentUser = false; - } - }, { - key: '_registerAuthenticationProvider', - value: function (provider) { - authProviders[provider.getAuthType()] = provider; - // Synchronize the current user with the auth provider. - ParseUser.currentAsync().then(function (current) { - if (current) { - current._synchronizeAuthData(provider.getAuthType()); - } - }); - } - }, { - key: '_logInWith', - value: function (provider, options) { - var user = new ParseUser(); - return user._linkWith(provider, options); - } - }, { - key: '_clearCache', - value: function () { - currentUserCache = null; - currentUserCacheMatchesDisk = false; - } - }, { - key: '_setCurrentUserCache', - value: function (user) { - currentUserCache = user; - } - }]); - return ParseUser; -}(_ParseObject3.default); - -exports.default = ParseUser; - -_ParseObject3.default.registerSubclass('_User', ParseUser); - -var DefaultController = { - updateUserOnDisk: function (user) { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var json = user.toJSON(); - json.className = '_User'; - return _Storage2.default.setItemAsync(path, (0, _stringify2.default)(json)).then(function () { - return user; - }); - }, - removeUserFromDisk: function () { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - currentUserCacheMatchesDisk = true; - currentUserCache = null; - return _Storage2.default.removeItemAsync(path); - }, - setCurrentUser: function (user) { - currentUserCache = user; - user._cleanupAuthData(); - user._synchronizeAllAuthData(); - return DefaultController.updateUserOnDisk(user); - }, - currentUser: function () { - if (currentUserCache) { - return currentUserCache; - } - if (currentUserCacheMatchesDisk) { - return null; - } - if (_Storage2.default.async()) { - throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); - } - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var userData = _Storage2.default.getItem(path); - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return null; - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = _ParseObject3.default.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return current; - }, - currentUserAsync: function () { - if (currentUserCache) { - return _ParsePromise2.default.as(currentUserCache); - } - if (currentUserCacheMatchesDisk) { - return _ParsePromise2.default.as(null); - } - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - return _Storage2.default.getItemAsync(path).then(function (userData) { - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return _ParsePromise2.default.as(null); - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = _ParseObject3.default.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return _ParsePromise2.default.as(current); - }); - }, - signUp: function (user, attrs, options) { - var username = attrs && attrs.username || user.get('username'); - var password = attrs && attrs.password || user.get('password'); - - if (!username || !username.length) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); - } - if (!password || !password.length) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); - } - - return user.save(attrs, options).then(function () { - // Clear the password field - user._finishFetch({ password: undefined }); - - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - }, - logIn: function (user, options) { - var RESTController = _CoreManager2.default.getRESTController(); - var stateController = _CoreManager2.default.getObjectStateController(); - var auth = { - username: user.get('username'), - password: user.get('password') - }; - return RESTController.request('GET', 'login', auth, options).then(function (response, status) { - user._migrateId(response.objectId); - user._setExisted(true); - stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); - stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); - response.password = undefined; - user._finishFetch(response); - if (!canUseCurrentUser) { - // We can't set the current user, so just return the one we logged in - return _ParsePromise2.default.as(user); - } - return DefaultController.setCurrentUser(user); - }); - }, - become: function (options) { - var user = new ParseUser(); - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('GET', 'users/me', {}, options).then(function (response, status) { - user._finishFetch(response); - user._setExisted(true); - return DefaultController.setCurrentUser(user); - }); - }, - logOut: function () { - return DefaultController.currentUserAsync().then(function (currentUser) { - var path = _Storage2.default.generatePath(CURRENT_USER_KEY); - var promise = _Storage2.default.removeItemAsync(path); - var RESTController = _CoreManager2.default.getRESTController(); - if (currentUser !== null) { - var currentSession = currentUser.getSessionToken(); - if (currentSession && (0, _isRevocableSession2.default)(currentSession)) { - promise = promise.then(function () { - return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); - }); - } - currentUser._logOutWithAll(); - currentUser._finishFetch({ sessionToken: undefined }); - } - currentUserCacheMatchesDisk = true; - currentUserCache = null; - - return promise; - }); - }, - requestPasswordReset: function (email, options) { - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); - }, - upgradeToRevocableSession: function (user, options) { - var token = user.getSessionToken(); - if (!token) { - return _ParsePromise2.default.error(new _ParseError2.default(_ParseError2.default.SESSION_MISSING, 'Cannot upgrade a user with no session token')); - } - - options.sessionToken = token; - - var RESTController = _CoreManager2.default.getRESTController(); - return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(function (result) { - var session = new _ParseSession2.default(); - session._finishFetch(result); - user._finishFetch({ sessionToken: session.getSessionToken() }); - if (user.isCurrent()) { - return DefaultController.setCurrentUser(user); - } - return _ParsePromise2.default.as(user); - }); - }, - linkWith: function (user, authData) { - return user.save({ authData: authData }).then(function () { - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - } -}; - -_CoreManager2.default.setUserController(DefaultController); \ No newline at end of file diff --git a/lib/node/Push.js b/lib/node/Push.js deleted file mode 100644 index cfb740767..000000000 --- a/lib/node/Push.js +++ /dev/null @@ -1,98 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.send = send; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParseQuery = require('./ParseQuery'); - -var _ParseQuery2 = _interopRequireDefault(_ParseQuery); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Contains functions to deal with Push in Parse. - * @class Parse.Push - * @static - */ - -/** - * Sends a push notification. - * @method send - * @param {Object} data - The data of the push notification. Valid fields - * are: - *
                            - *
                          1. channels - An Array of channels to push to.
                          2. - *
                          3. push_time - A Date object for when to send the push.
                          4. - *
                          5. expiration_time - A Date object for when to expire - * the push.
                          6. - *
                          7. expiration_interval - The seconds from now to expire the push.
                          8. - *
                          9. where - A Parse.Query over Parse.Installation that is used to match - * a set of installations to push to.
                          10. - *
                          11. data - The data to send as part of the push
                          12. - *
                              - * @param {Object} options An object that has an optional success function, - * that takes no arguments and will be called on a successful push, and - * an error function that takes a Parse.Error and will be called if the push - * failed. - * @return {Parse.Promise} A promise that is fulfilled when the push request - * completes. - */ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function send(data, options) { - options = options || {}; - - if (data.where && data.where instanceof _ParseQuery2.default) { - data.where = data.where.toJSON().where; - } - - if (data.push_time && (0, _typeof3.default)(data.push_time) === 'object') { - data.push_time = data.push_time.toJSON(); - } - - if (data.expiration_time && (0, _typeof3.default)(data.expiration_time) === 'object') { - data.expiration_time = data.expiration_time.toJSON(); - } - - if (data.expiration_time && data.expiration_interval) { - throw new Error('expiration_time and expiration_interval cannot both be set.'); - } - - return _CoreManager2.default.getPushController().send(data, { - useMasterKey: options.useMasterKey - })._thenRunCallbacks(options); -} - -var DefaultController = { - send: function (data, options) { - var RESTController = _CoreManager2.default.getRESTController(); - - var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); - - return request._thenRunCallbacks(options); - } -}; - -_CoreManager2.default.setPushController(DefaultController); \ No newline at end of file diff --git a/lib/node/RESTController.js b/lib/node/RESTController.js deleted file mode 100644 index b8e0541c5..000000000 --- a/lib/node/RESTController.js +++ /dev/null @@ -1,250 +0,0 @@ -'use strict'; - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _stringify = require('babel-runtime/core-js/json/stringify'); - -var _stringify2 = _interopRequireDefault(_stringify); - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParseError = require('./ParseError'); - -var _ParseError2 = _interopRequireDefault(_ParseError); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _Storage = require('./Storage'); - -var _Storage2 = _interopRequireDefault(_Storage); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var XHR = null; -if (typeof XMLHttpRequest !== 'undefined') { - XHR = XMLHttpRequest; -} - -XHR = require('xmlhttprequest').XMLHttpRequest; - - -var useXDomainRequest = false; -if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { - useXDomainRequest = true; -} - -function ajaxIE9(method, url, data) { - var promise = new _ParsePromise2.default(); - var xdr = new XDomainRequest(); - xdr.onload = function () { - var response; - try { - response = JSON.parse(xdr.responseText); - } catch (e) { - promise.reject(e); - } - if (response) { - promise.resolve(response); - } - }; - xdr.onerror = xdr.ontimeout = function () { - // Let's fake a real error message. - var fakeResponse = { - responseText: (0, _stringify2.default)({ - code: _ParseError2.default.X_DOMAIN_REQUEST, - error: 'IE\'s XDomainRequest does not supply error info.' - }) - }; - promise.reject(fakeResponse); - }; - xdr.onprogress = function () {}; - xdr.open(method, url); - xdr.send(data); - return promise; -} - -var RESTController = { - ajax: function (method, url, data, headers) { - if (useXDomainRequest) { - return ajaxIE9(method, url, data, headers); - } - - var promise = new _ParsePromise2.default(); - var attempts = 0; - - (function dispatch() { - if (XHR == null) { - throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); - } - var handled = false; - var xhr = new XHR(); - - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4 || handled) { - return; - } - handled = true; - - if (xhr.status >= 200 && xhr.status < 300) { - var response; - try { - response = JSON.parse(xhr.responseText); - } catch (e) { - promise.reject(e.toString()); - } - if (response) { - promise.resolve(response, xhr.status, xhr); - } - } else if (xhr.status >= 500 || xhr.status === 0) { - // retry on 5XX or node-xmlhttprequest error - if (++attempts < _CoreManager2.default.get('REQUEST_ATTEMPT_LIMIT')) { - // Exponentially-growing random delay - var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); - setTimeout(dispatch, delay); - } else if (xhr.status === 0) { - promise.reject('Unable to connect to the Parse API'); - } else { - // After the retry limit is reached, fail - promise.reject(xhr); - } - } else { - promise.reject(xhr); - } - }; - - headers = headers || {}; - if (typeof headers['Content-Type'] !== 'string') { - headers['Content-Type'] = 'text/plain'; // Avoid pre-flight - } - if (_CoreManager2.default.get('IS_NODE')) { - headers['User-Agent'] = 'Parse/' + _CoreManager2.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; - } - - xhr.open(method, url, true); - for (var h in headers) { - xhr.setRequestHeader(h, headers[h]); - } - xhr.send(data); - })(); - - return promise; - }, - request: function (method, path, data, options) { - options = options || {}; - var url = _CoreManager2.default.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += path; - - var payload = {}; - if (data && (typeof data === 'undefined' ? 'undefined' : (0, _typeof3.default)(data)) === 'object') { - for (var k in data) { - payload[k] = data[k]; - } - } - - if (method !== 'POST') { - payload._method = method; - method = 'POST'; - } - - payload._ApplicationId = _CoreManager2.default.get('APPLICATION_ID'); - var jsKey = _CoreManager2.default.get('JAVASCRIPT_KEY'); - if (jsKey) { - payload._JavaScriptKey = jsKey; - } - payload._ClientVersion = _CoreManager2.default.get('VERSION'); - - var useMasterKey = options.useMasterKey; - if (typeof useMasterKey === 'undefined') { - useMasterKey = _CoreManager2.default.get('USE_MASTER_KEY'); - } - if (useMasterKey) { - if (_CoreManager2.default.get('MASTER_KEY')) { - delete payload._JavaScriptKey; - payload._MasterKey = _CoreManager2.default.get('MASTER_KEY'); - } else { - throw new Error('Cannot use the Master Key, it has not been provided.'); - } - } - - if (_CoreManager2.default.get('FORCE_REVOCABLE_SESSION')) { - payload._RevocableSession = '1'; - } - - var installationId = options.installationId; - var installationIdPromise; - if (installationId && typeof installationId === 'string') { - installationIdPromise = _ParsePromise2.default.as(installationId); - } else { - var installationController = _CoreManager2.default.getInstallationController(); - installationIdPromise = installationController.currentInstallationId(); - } - - return installationIdPromise.then(function (iid) { - payload._InstallationId = iid; - var userController = _CoreManager2.default.getUserController(); - if (options && typeof options.sessionToken === 'string') { - return _ParsePromise2.default.as(options.sessionToken); - } else if (userController) { - return userController.currentUserAsync().then(function (user) { - if (user) { - return _ParsePromise2.default.as(user.getSessionToken()); - } - return _ParsePromise2.default.as(null); - }); - } - return _ParsePromise2.default.as(null); - }).then(function (token) { - if (token) { - payload._SessionToken = token; - } - - var payloadString = (0, _stringify2.default)(payload); - - return RESTController.ajax(method, url, payloadString); - }).then(null, function (response) { - // Transform the error into an instance of ParseError by trying to parse - // the error string as JSON - var error; - if (response && response.responseText) { - try { - var errorJSON = JSON.parse(response.responseText); - error = new _ParseError2.default(errorJSON.code, errorJSON.error); - } catch (e) { - // If we fail to parse the error text, that's okay. - error = new _ParseError2.default(_ParseError2.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); - } - } else { - error = new _ParseError2.default(_ParseError2.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + (0, _stringify2.default)(response)); - } - - return _ParsePromise2.default.error(error); - }); - }, - _setXHR: function (xhr) { - XHR = xhr; - } -}; - -module.exports = RESTController; \ No newline at end of file diff --git a/lib/node/SingleInstanceStateController.js b/lib/node/SingleInstanceStateController.js deleted file mode 100644 index 545dd4c5d..000000000 --- a/lib/node/SingleInstanceStateController.js +++ /dev/null @@ -1,160 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.getState = getState; -exports.initializeState = initializeState; -exports.removeState = removeState; -exports.getServerData = getServerData; -exports.setServerData = setServerData; -exports.getPendingOps = getPendingOps; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.getObjectCache = getObjectCache; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; -exports.enqueueTask = enqueueTask; -exports.clearAllState = clearAllState; -exports.duplicateState = duplicateState; - -var _ObjectStateMutations = require('./ObjectStateMutations'); - -var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -var objectState = {}; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function getState(obj) { - var classData = objectState[obj.className]; - if (classData) { - return classData[obj.id] || null; - } - return null; -} - -function initializeState(obj, initial) { - var state = getState(obj); - if (state) { - return state; - } - if (!objectState[obj.className]) { - objectState[obj.className] = {}; - } - if (!initial) { - initial = ObjectStateMutations.defaultState(); - } - state = objectState[obj.className][obj.id] = initial; - return state; -} - -function removeState(obj) { - var state = getState(obj); - if (state === null) { - return null; - } - delete objectState[obj.className][obj.id]; - return state; -} - -function getServerData(obj) { - var state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -function setServerData(obj, attributes) { - var serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -function getPendingOps(obj) { - var state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -function setPendingOp(obj, attr, op) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -function pushPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -function popPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -function mergeFirstPendingState(obj) { - var pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -function getObjectCache(obj) { - var state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -function estimateAttribute(obj, attr) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -function estimateAttributes(obj) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -function commitServerChanges(obj, changes) { - var state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -function enqueueTask(obj, task) { - var state = initializeState(obj); - return state.tasks.enqueue(task); -} - -function clearAllState() { - objectState = {}; -} - -function duplicateState(source, dest) { - dest.id = source.id; -} \ No newline at end of file diff --git a/lib/node/Storage.js b/lib/node/Storage.js deleted file mode 100644 index e4cd978a5..000000000 --- a/lib/node/Storage.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -var _CoreManager = require('./CoreManager'); - -var _CoreManager2 = _interopRequireDefault(_CoreManager); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = { - async: function () { - var controller = _CoreManager2.default.getStorageController(); - return !!controller.async; - }, - getItem: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.getItem(path); - }, - getItemAsync: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.getItemAsync(path); - } - return _ParsePromise2.default.as(controller.getItem(path)); - }, - setItem: function (path, value) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.setItem(path, value); - }, - setItemAsync: function (path, value) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.setItemAsync(path, value); - } - return _ParsePromise2.default.as(controller.setItem(path, value)); - }, - removeItem: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.removeItem(path); - }, - removeItemAsync: function (path) { - var controller = _CoreManager2.default.getStorageController(); - if (controller.async === 1) { - return controller.removeItemAsync(path); - } - return _ParsePromise2.default.as(controller.removeItem(path)); - }, - generatePath: function (path) { - if (!_CoreManager2.default.get('APPLICATION_ID')) { - throw new Error('You need to call Parse.initialize before using Parse.'); - } - if (typeof path !== 'string') { - throw new Error('Tried to get a Storage path that was not a String.'); - } - if (path[0] === '/') { - path = path.substr(1); - } - return 'Parse/' + _CoreManager2.default.get('APPLICATION_ID') + '/' + path; - }, - _clear: function () { - var controller = _CoreManager2.default.getStorageController(); - if (controller.hasOwnProperty('clear')) { - controller.clear(); - } - } -}; - -_CoreManager2.default.setStorageController(require('./StorageController.default')); \ No newline at end of file diff --git a/lib/node/StorageController.browser.js b/lib/node/StorageController.browser.js deleted file mode 100644 index d372924a0..000000000 --- a/lib/node/StorageController.browser.js +++ /dev/null @@ -1,41 +0,0 @@ -'use strict'; - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var StorageController = { - async: 0, - - getItem: function (path) { - return localStorage.getItem(path); - }, - setItem: function (path, value) { - try { - localStorage.setItem(path, value); - } catch (e) { - // Quota exceeded, possibly due to Safari Private Browsing mode - } - }, - removeItem: function (path) { - localStorage.removeItem(path); - }, - clear: function () { - localStorage.clear(); - } -}; /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/node/StorageController.default.js b/lib/node/StorageController.default.js deleted file mode 100644 index 460c1e2ca..000000000 --- a/lib/node/StorageController.default.js +++ /dev/null @@ -1,41 +0,0 @@ -"use strict"; - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -// When there is no native storage interface, we default to an in-memory map - -var memMap = {}; -var StorageController = { - async: 0, - - getItem: function (path) { - if (memMap.hasOwnProperty(path)) { - return memMap[path]; - } - return null; - }, - setItem: function (path, value) { - memMap[path] = String(value); - }, - removeItem: function (path) { - delete memMap[path]; - }, - clear: function () { - for (var key in memMap) { - if (memMap.hasOwnProperty(key)) { - delete memMap[key]; - } - } - } -}; - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/node/StorageController.react-native.js b/lib/node/StorageController.react-native.js deleted file mode 100644 index b92ae6141..000000000 --- a/lib/node/StorageController.react-native.js +++ /dev/null @@ -1,67 +0,0 @@ -'use strict'; - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -var _reactNative = require('react-native/Libraries/react-native/react-native.js'); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var StorageController = { - async: 1, - - getItemAsync: function (path) { - var p = new _ParsePromise2.default(); - _reactNative.AsyncStorage.getItem(path, function (err, value) { - if (err) { - p.reject(err); - } else { - p.resolve(value); - } - }); - return p; - }, - setItemAsync: function (path, value) { - var p = new _ParsePromise2.default(); - _reactNative.AsyncStorage.setItem(path, value, function (err) { - if (err) { - p.reject(err); - } else { - p.resolve(value); - } - }); - return p; - }, - removeItemAsync: function (path) { - var p = new _ParsePromise2.default(); - _reactNative.AsyncStorage.removeItem(path, function (err) { - if (err) { - p.reject(err); - } else { - p.resolve(); - } - }); - return p; - }, - clear: function () { - _reactNative.AsyncStorage.clear(); - } -}; -// RN packager nonsense - - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/node/TaskQueue.js b/lib/node/TaskQueue.js deleted file mode 100644 index 4bf6bffd0..000000000 --- a/lib/node/TaskQueue.js +++ /dev/null @@ -1,77 +0,0 @@ -'use strict'; - -var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); - -var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); - -var _createClass2 = require('babel-runtime/helpers/createClass'); - -var _createClass3 = _interopRequireDefault(_createClass2); - -var _ParsePromise = require('./ParsePromise'); - -var _ParsePromise2 = _interopRequireDefault(_ParsePromise); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -var TaskQueue = function () { - function TaskQueue() { - (0, _classCallCheck3.default)(this, TaskQueue); - - this.queue = []; - } - - (0, _createClass3.default)(TaskQueue, [{ - key: 'enqueue', - value: function (task) { - var _this = this; - - var taskComplete = new _ParsePromise2.default(); - this.queue.push({ - task: task, - _completion: taskComplete - }); - if (this.queue.length === 1) { - task().then(function () { - _this._dequeue(); - taskComplete.resolve(); - }, function (error) { - _this._dequeue(); - taskComplete.reject(error); - }); - } - return taskComplete; - } - }, { - key: '_dequeue', - value: function () { - var _this2 = this; - - this.queue.shift(); - if (this.queue.length) { - var next = this.queue[0]; - next.task().then(function () { - _this2._dequeue(); - next._completion.resolve(); - }, function (error) { - _this2._dequeue(); - next._completion.reject(error); - }); - } - } - }]); - return TaskQueue; -}(); /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -module.exports = TaskQueue; \ No newline at end of file diff --git a/lib/node/UniqueInstanceStateController.js b/lib/node/UniqueInstanceStateController.js deleted file mode 100644 index 12b8ab04d..000000000 --- a/lib/node/UniqueInstanceStateController.js +++ /dev/null @@ -1,189 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _weakMap = require('babel-runtime/core-js/weak-map'); - -var _weakMap2 = _interopRequireDefault(_weakMap); - -exports.getState = getState; -exports.initializeState = initializeState; -exports.removeState = removeState; -exports.getServerData = getServerData; -exports.setServerData = setServerData; -exports.getPendingOps = getPendingOps; -exports.setPendingOp = setPendingOp; -exports.pushPendingState = pushPendingState; -exports.popPendingState = popPendingState; -exports.mergeFirstPendingState = mergeFirstPendingState; -exports.getObjectCache = getObjectCache; -exports.estimateAttribute = estimateAttribute; -exports.estimateAttributes = estimateAttributes; -exports.commitServerChanges = commitServerChanges; -exports.enqueueTask = enqueueTask; -exports.duplicateState = duplicateState; -exports.clearAllState = clearAllState; - -var _ObjectStateMutations = require('./ObjectStateMutations'); - -var ObjectStateMutations = _interopRequireWildcard(_ObjectStateMutations); - -var _TaskQueue = require('./TaskQueue'); - -var _TaskQueue2 = _interopRequireDefault(_TaskQueue); - -function _interopRequireWildcard(obj) { - if (obj && obj.__esModule) { - return obj; - } else { - var newObj = {};if (obj != null) { - for (var key in obj) { - if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; - } - }newObj.default = obj;return newObj; - } -} - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var objectState = new _weakMap2.default(); - -function getState(obj) { - var classData = objectState.get(obj); - return classData || null; -} - -function initializeState(obj, initial) { - var state = getState(obj); - if (state) { - return state; - } - if (!initial) { - initial = { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new _TaskQueue2.default(), - existed: false - }; - } - state = initial; - objectState.set(obj, state); - return state; -} - -function removeState(obj) { - var state = getState(obj); - if (state === null) { - return null; - } - objectState.delete(obj); - return state; -} - -function getServerData(obj) { - var state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -function setServerData(obj, attributes) { - var serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -function getPendingOps(obj) { - var state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -function setPendingOp(obj, attr, op) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -function pushPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -function popPendingState(obj) { - var pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -function mergeFirstPendingState(obj) { - var pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -function getObjectCache(obj) { - var state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -function estimateAttribute(obj, attr) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -function estimateAttributes(obj) { - var serverData = getServerData(obj); - var pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -function commitServerChanges(obj, changes) { - var state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -function enqueueTask(obj, task) { - var state = initializeState(obj); - return state.tasks.enqueue(task); -} - -function duplicateState(source, dest) { - var oldState = initializeState(source); - var newState = initializeState(dest); - for (var key in oldState.serverData) { - newState.serverData[key] = oldState.serverData[key]; - } - for (var index = 0; index < oldState.pendingOps.length; index++) { - for (var _key in oldState.pendingOps[index]) { - newState.pendingOps[index][_key] = oldState.pendingOps[index][_key]; - } - } - for (var _key2 in oldState.objectCache) { - newState.objectCache[_key2] = oldState.objectCache[_key2]; - } - newState.existed = oldState.existed; -} - -function clearAllState() { - objectState = new _weakMap2.default(); -} \ No newline at end of file diff --git a/lib/node/arrayContainsObject.js b/lib/node/arrayContainsObject.js deleted file mode 100644 index e9d7949c9..000000000 --- a/lib/node/arrayContainsObject.js +++ /dev/null @@ -1,35 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = arrayContainsObject; - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function arrayContainsObject(array, object) { - if (array.indexOf(object) > -1) { - return true; - } - for (var i = 0; i < array.length; i++) { - if (array[i] instanceof _ParseObject2.default && array[i].className === object.className && array[i]._getId() === object._getId()) { - return true; - } - } - return false; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ \ No newline at end of file diff --git a/lib/node/canBeSerialized.js b/lib/node/canBeSerialized.js deleted file mode 100644 index e7b7e2282..000000000 --- a/lib/node/canBeSerialized.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = canBeSerialized; - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -function canBeSerialized(obj) { - if (!(obj instanceof _ParseObject2.default)) { - return true; - } - var attributes = obj.attributes; - for (var attr in attributes) { - var val = attributes[attr]; - if (!canBeSerializedHelper(val)) { - return false; - } - } - return true; -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function canBeSerializedHelper(value) { - if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { - return true; - } - if (value instanceof _ParseRelation2.default) { - return true; - } - if (value instanceof _ParseObject2.default) { - return !!value.id; - } - if (value instanceof _ParseFile2.default) { - if (value.url()) { - return true; - } - return false; - } - if (Array.isArray(value)) { - for (var i = 0; i < value.length; i++) { - if (!canBeSerializedHelper(value[i])) { - return false; - } - } - return true; - } - for (var k in value) { - if (!canBeSerializedHelper(value[k])) { - return false; - } - } - return true; -} \ No newline at end of file diff --git a/lib/node/decode.js b/lib/node/decode.js deleted file mode 100644 index 98a182789..000000000 --- a/lib/node/decode.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = decode; - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseOp = require('./ParseOp'); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function decode(value) { - if (value === null || (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) !== 'object') { - return value; - } - if (Array.isArray(value)) { - var dup = []; - value.forEach(function (v, i) { - dup[i] = decode(v); - }); - return dup; - } - if (typeof value.__op === 'string') { - return (0, _ParseOp.opFromJSON)(value); - } - if (value.__type === 'Pointer' && value.className) { - return _ParseObject2.default.fromJSON(value); - } - if (value.__type === 'Object' && value.className) { - return _ParseObject2.default.fromJSON(value); - } - if (value.__type === 'Relation') { - // The parent and key fields will be populated by the parent - var relation = new _ParseRelation2.default(null, null); - relation.targetClassName = value.className; - return relation; - } - if (value.__type === 'Date') { - return new Date(value.iso); - } - if (value.__type === 'File') { - return _ParseFile2.default.fromJSON(value); - } - if (value.__type === 'GeoPoint') { - return new _ParseGeoPoint2.default({ - latitude: value.latitude, - longitude: value.longitude - }); - } - var copy = {}; - for (var k in value) { - copy[k] = decode(value[k]); - } - return copy; -} \ No newline at end of file diff --git a/lib/node/encode.js b/lib/node/encode.js deleted file mode 100644 index 8c3aee6e3..000000000 --- a/lib/node/encode.js +++ /dev/null @@ -1,104 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -exports.default = function (value, disallowObjects, forcePointers, seen) { - return encode(value, !!disallowObjects, !!forcePointers, seen || []); -}; - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseOp = require('./ParseOp'); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var toString = Object.prototype.toString; - -function encode(value, disallowObjects, forcePointers, seen) { - if (value instanceof _ParseObject2.default) { - if (disallowObjects) { - throw new Error('Parse Objects not allowed here'); - } - var seenEntry = value.id ? value.className + ':' + value.id : value; - if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || (0, _keys2.default)(value._getServerData()).length < 1) { - return value.toPointer(); - } - seen = seen.concat(seenEntry); - return value._toFullJSON(seen); - } - if (value instanceof _ParseOp.Op || value instanceof _ParseACL2.default || value instanceof _ParseGeoPoint2.default || value instanceof _ParseRelation2.default) { - return value.toJSON(); - } - if (value instanceof _ParseFile2.default) { - if (!value.url()) { - throw new Error('Tried to encode an unsaved file.'); - } - return value.toJSON(); - } - if (toString.call(value) === '[object Date]') { - if (isNaN(value)) { - throw new Error('Tried to encode an invalid date.'); - } - return { __type: 'Date', iso: value.toJSON() }; - } - if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { - return value.source; - } - - if (Array.isArray(value)) { - return value.map(function (v) { - return encode(v, disallowObjects, forcePointers, seen); - }); - } - - if (value && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3.default)(value)) === 'object') { - var output = {}; - for (var k in value) { - output[k] = encode(value[k], disallowObjects, forcePointers, seen); - } - return output; - } - - return value; -} \ No newline at end of file diff --git a/lib/node/equals.js b/lib/node/equals.js deleted file mode 100644 index 32edcc8a7..000000000 --- a/lib/node/equals.js +++ /dev/null @@ -1,84 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _keys = require('babel-runtime/core-js/object/keys'); - -var _keys2 = _interopRequireDefault(_keys); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = equals; - -var _ParseACL = require('./ParseACL'); - -var _ParseACL2 = _interopRequireDefault(_ParseACL); - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseGeoPoint = require('./ParseGeoPoint'); - -var _ParseGeoPoint2 = _interopRequireDefault(_ParseGeoPoint); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -function equals(a, b) { - if ((typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== (typeof b === 'undefined' ? 'undefined' : (0, _typeof3.default)(b))) { - return false; - } - - if (!a || (typeof a === 'undefined' ? 'undefined' : (0, _typeof3.default)(a)) !== 'object') { - // a is a primitive - return a === b; - } - - if (Array.isArray(a) || Array.isArray(b)) { - if (!Array.isArray(a) || !Array.isArray(b)) { - return false; - } - if (a.length !== b.length) { - return false; - } - for (var i = a.length; i--;) { - if (!equals(a[i], b[i])) { - return false; - } - } - return true; - } - - if (a instanceof _ParseACL2.default || a instanceof _ParseFile2.default || a instanceof _ParseGeoPoint2.default || a instanceof _ParseObject2.default) { - return a.equals(b); - } - - if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) { - return false; - } - for (var k in a) { - if (!equals(a[k], b[k])) { - return false; - } - } - return true; -} \ No newline at end of file diff --git a/lib/node/escape.js b/lib/node/escape.js deleted file mode 100644 index 4693baaed..000000000 --- a/lib/node/escape.js +++ /dev/null @@ -1,31 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = escape; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var encoded = { - '&': '&', - '<': '<', - '>': '>', - '/': '/', - '\'': ''', - '"': '"' -}; - -function escape(str) { - return str.replace(/[&<>\/'"]/g, function (char) { - return encoded[char]; - }); -} \ No newline at end of file diff --git a/lib/node/isRevocableSession.js b/lib/node/isRevocableSession.js deleted file mode 100644 index 92b8230e9..000000000 --- a/lib/node/isRevocableSession.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = isRevocableSession; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function isRevocableSession(token) { - return token.indexOf('r:') > -1; -} \ No newline at end of file diff --git a/lib/node/parseDate.js b/lib/node/parseDate.js deleted file mode 100644 index 48e061b05..000000000 --- a/lib/node/parseDate.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = parseDate; -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function parseDate(iso8601) { - var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); - var match = regexp.exec(iso8601); - if (!match) { - return null; - } - - var year = match[1] || 0; - var month = (match[2] || 1) - 1; - var day = match[3] || 0; - var hour = match[4] || 0; - var minute = match[5] || 0; - var second = match[6] || 0; - var milli = match[8] || 0; - - return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); -} \ No newline at end of file diff --git a/lib/node/unique.js b/lib/node/unique.js deleted file mode 100644 index 157b3560a..000000000 --- a/lib/node/unique.js +++ /dev/null @@ -1,45 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); -exports.default = unique; - -var _arrayContainsObject = require('./arrayContainsObject'); - -var _arrayContainsObject2 = _interopRequireDefault(_arrayContainsObject); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function unique(arr) { - var uniques = []; - arr.forEach(function (value) { - if (value instanceof _ParseObject2.default) { - if (!(0, _arrayContainsObject2.default)(uniques, value)) { - uniques.push(value); - } - } else { - if (uniques.indexOf(value) < 0) { - uniques.push(value); - } - } - }); - return uniques; -} \ No newline at end of file diff --git a/lib/node/unsavedChildren.js b/lib/node/unsavedChildren.js deleted file mode 100644 index 073efd70b..000000000 --- a/lib/node/unsavedChildren.js +++ /dev/null @@ -1,102 +0,0 @@ -'use strict'; - -Object.defineProperty(exports, "__esModule", { - value: true -}); - -var _typeof2 = require('babel-runtime/helpers/typeof'); - -var _typeof3 = _interopRequireDefault(_typeof2); - -exports.default = unsavedChildren; - -var _ParseFile = require('./ParseFile'); - -var _ParseFile2 = _interopRequireDefault(_ParseFile); - -var _ParseObject = require('./ParseObject'); - -var _ParseObject2 = _interopRequireDefault(_ParseObject); - -var _ParseRelation = require('./ParseRelation'); - -var _ParseRelation2 = _interopRequireDefault(_ParseRelation); - -function _interopRequireDefault(obj) { - return obj && obj.__esModule ? obj : { default: obj }; -} - -/** - * Return an array of unsaved children, which are either Parse Objects or Files. - * If it encounters any dirty Objects without Ids, it will throw an exception. - */ -function unsavedChildren(obj, allowDeepUnsaved) { - var encountered = { - objects: {}, - files: [] - }; - var identifier = obj.className + ':' + obj._getId(); - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if ((0, _typeof3.default)(attributes[attr]) === 'object') { - traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); - } - } - var unsaved = []; - for (var id in encountered.objects) { - if (id !== identifier && encountered.objects[id] !== true) { - unsaved.push(encountered.objects[id]); - } - } - return unsaved.concat(encountered.files); -} /** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { - if (obj instanceof _ParseObject2.default) { - if (!obj.id && shouldThrow) { - throw new Error('Cannot create a pointer to an unsaved Object.'); - } - var identifier = obj.className + ':' + obj._getId(); - if (!encountered.objects[identifier]) { - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if ((0, _typeof3.default)(attributes[attr]) === 'object') { - traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); - } - } - } - return; - } - if (obj instanceof _ParseFile2.default) { - if (!obj.url() && encountered.files.indexOf(obj) < 0) { - encountered.files.push(obj); - } - return; - } - if (obj instanceof _ParseRelation2.default) { - return; - } - if (Array.isArray(obj)) { - obj.forEach(function (el) { - if ((typeof el === 'undefined' ? 'undefined' : (0, _typeof3.default)(el)) === 'object') { - traverse(el, encountered, shouldThrow, allowDeepUnsaved); - } - }); - } - for (var k in obj) { - if ((0, _typeof3.default)(obj[k]) === 'object') { - traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); - } - } -} \ No newline at end of file diff --git a/lib/react-native/Analytics.js b/lib/react-native/Analytics.js deleted file mode 100644 index 92561a2bb..000000000 --- a/lib/react-native/Analytics.js +++ /dev/null @@ -1,78 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; - -/** - * Parse.Analytics provides an interface to Parse's logging and analytics - * backend. - * - * @class Parse.Analytics - * @static - */ - -/** - * Tracks the occurrence of a custom event with additional dimensions. - * Parse will store a data point at the time of invocation with the given - * event name. - * - * Dimensions will allow segmentation of the occurrences of this custom - * event. Keys and values should be {@code String}s, and will throw - * otherwise. - * - * To track a user signup along with additional metadata, consider the - * following: - *
                              - * var dimensions = {
                              - *  gender: 'm',
                              - *  source: 'web',
                              - *  dayType: 'weekend'
                              - * };
                              - * Parse.Analytics.track('signup', dimensions);
                              - * 
                              - * - * There is a default limit of 8 dimensions per event tracked. - * - * @method track - * @param {String} name The name of the custom event to report to Parse as - * having happened. - * @param {Object} dimensions The dictionary of information by which to - * segment this event. - * @param {Object} options A Backbone-style callback object. - * @return {Parse.Promise} A promise that is resolved when the round-trip - * to the server completes. - */ -export function track(name, dimensions, options) { - name = name || ''; - name = name.replace(/^\s*/, ''); - name = name.replace(/\s*$/, ''); - if (name.length === 0) { - throw new TypeError('A name for the custom event must be provided'); - } - - for (var key in dimensions) { - if (typeof key !== 'string' || typeof dimensions[key] !== 'string') { - throw new TypeError('track() dimensions expects keys and values of type "string".'); - } - } - - options = options || {}; - return CoreManager.getAnalyticsController().track(name, dimensions)._thenRunCallbacks(options); -} - -var DefaultController = { - track(name, dimensions) { - var RESTController = CoreManager.getRESTController(); - return RESTController.request('POST', 'events/' + name, { dimensions: dimensions }); - } -}; - -CoreManager.setAnalyticsController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/Cloud.js b/lib/react-native/Cloud.js deleted file mode 100644 index 604707acd..000000000 --- a/lib/react-native/Cloud.js +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import decode from './decode'; -import encode from './encode'; -import ParseError from './ParseError'; -import ParsePromise from './ParsePromise'; - -/** - * Contains functions for calling and declaring - * cloud functions. - *

                              - * Some functions are only available from Cloud Code. - *

                              - * - * @class Parse.Cloud - * @static - */ - -/** - * Makes a call to a cloud function. - * @method run - * @param {String} name The function name. - * @param {Object} data The parameters to send to the cloud function. - * @param {Object} options A Backbone-style options object - * options.success, if set, should be a function to handle a successful - * call to a cloud function. options.error should be a function that - * handles an error running the cloud function. Both functions are - * optional. Both functions take a single argument. - * @return {Parse.Promise} A promise that will be resolved with the result - * of the function. - */ -export function run(name, data, options) { - options = options || {}; - - if (typeof name !== 'string' || name.length === 0) { - throw new TypeError('Cloud function name must be a string.'); - } - - var requestOptions = {}; - if (options.useMasterKey) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.sessionToken) { - requestOptions.sessionToken = options.sessionToken; - } - - return CoreManager.getCloudController().run(name, data, requestOptions)._thenRunCallbacks(options); -} - -var DefaultController = { - run(name, data, options) { - var RESTController = CoreManager.getRESTController(); - - var payload = encode(data, true); - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - requestOptions.sessionToken = options.sessionToken; - } - - var request = RESTController.request('POST', 'functions/' + name, payload, requestOptions); - - return request.then(function (res) { - var decoded = decode(res); - if (decoded && decoded.hasOwnProperty('result')) { - return ParsePromise.as(decoded.result); - } - return ParsePromise.error(new ParseError(ParseError.INVALID_JSON, 'The server returned an invalid response.')); - })._thenRunCallbacks(options); - } -}; - -CoreManager.setCloudController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/CoreManager.js b/lib/react-native/CoreManager.js deleted file mode 100644 index 97062e559..000000000 --- a/lib/react-native/CoreManager.js +++ /dev/null @@ -1,188 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var config = { - // Defaults - IS_NODE: typeof process !== 'undefined' && !!process.versions && !!process.versions.node && !process.versions.electron, - REQUEST_ATTEMPT_LIMIT: 5, - SERVER_URL: 'https://api.parse.com/1', - LIVEQUERY_SERVER_URL: null, - VERSION: 'js' + '1.9.2', - APPLICATION_ID: null, - JAVASCRIPT_KEY: null, - MASTER_KEY: null, - USE_MASTER_KEY: false, - PERFORM_USER_REWRITE: true, - FORCE_REVOCABLE_SESSION: false -}; - -function requireMethods(name, methods, controller) { - methods.forEach(func => { - if (typeof controller[func] !== 'function') { - throw new Error(`${name} must implement ${func}()`); - } - }); -} - -module.exports = { - get: function (key) { - if (config.hasOwnProperty(key)) { - return config[key]; - } - throw new Error('Configuration key not found: ' + key); - }, - - set: function (key, value) { - config[key] = value; - }, - - /* Specialized Controller Setters/Getters */ - - setAnalyticsController(controller) { - requireMethods('AnalyticsController', ['track'], controller); - config['AnalyticsController'] = controller; - }, - - getAnalyticsController() { - return config['AnalyticsController']; - }, - - setCloudController(controller) { - requireMethods('CloudController', ['run'], controller); - config['CloudController'] = controller; - }, - - getCloudController() { - return config['CloudController']; - }, - - setConfigController(controller) { - requireMethods('ConfigController', ['current', 'get'], controller); - config['ConfigController'] = controller; - }, - - getConfigController() { - return config['ConfigController']; - }, - - setFileController(controller) { - requireMethods('FileController', ['saveFile', 'saveBase64'], controller); - config['FileController'] = controller; - }, - - getFileController() { - return config['FileController']; - }, - - setInstallationController(controller) { - requireMethods('InstallationController', ['currentInstallationId'], controller); - config['InstallationController'] = controller; - }, - - getInstallationController() { - return config['InstallationController']; - }, - - setObjectController(controller) { - requireMethods('ObjectController', ['save', 'fetch', 'destroy'], controller); - config['ObjectController'] = controller; - }, - - getObjectController() { - return config['ObjectController']; - }, - - setObjectStateController(controller) { - requireMethods('ObjectStateController', ['getState', 'initializeState', 'removeState', 'getServerData', 'setServerData', 'getPendingOps', 'setPendingOp', 'pushPendingState', 'popPendingState', 'mergeFirstPendingState', 'getObjectCache', 'estimateAttribute', 'estimateAttributes', 'commitServerChanges', 'enqueueTask', 'clearAllState'], controller); - - config['ObjectStateController'] = controller; - }, - - getObjectStateController() { - return config['ObjectStateController']; - }, - - setPushController(controller) { - requireMethods('PushController', ['send'], controller); - config['PushController'] = controller; - }, - - getPushController() { - return config['PushController']; - }, - - setQueryController(controller) { - requireMethods('QueryController', ['find'], controller); - config['QueryController'] = controller; - }, - - getQueryController() { - return config['QueryController']; - }, - - setRESTController(controller) { - requireMethods('RESTController', ['request', 'ajax'], controller); - config['RESTController'] = controller; - }, - - getRESTController() { - return config['RESTController']; - }, - - setSessionController(controller) { - requireMethods('SessionController', ['getSession'], controller); - config['SessionController'] = controller; - }, - - getSessionController() { - return config['SessionController']; - }, - - setStorageController(controller) { - if (controller.async) { - requireMethods('An async StorageController', ['getItemAsync', 'setItemAsync', 'removeItemAsync'], controller); - } else { - requireMethods('A synchronous StorageController', ['getItem', 'setItem', 'removeItem'], controller); - } - config['StorageController'] = controller; - }, - - getStorageController() { - return config['StorageController']; - }, - - setUserController(controller) { - requireMethods('UserController', ['setCurrentUser', 'currentUser', 'currentUserAsync', 'signUp', 'logIn', 'become', 'logOut', 'requestPasswordReset', 'upgradeToRevocableSession', 'linkWith'], controller); - config['UserController'] = controller; - }, - - getUserController() { - return config['UserController']; - }, - - setLiveQueryController(controller) { - requireMethods('LiveQueryController', ['subscribe', 'unsubscribe', 'open', 'close'], controller); - config['LiveQueryController'] = controller; - }, - - getLiveQueryController() { - return config['LiveQueryController']; - }, - - setHooksController(controller) { - requireMethods('HooksController', ['create', 'get', 'update', 'remove'], controller); - config['HooksController'] = controller; - }, - - getHooksController() { - return config['HooksController']; - } -}; \ No newline at end of file diff --git a/lib/react-native/EventEmitter.js b/lib/react-native/EventEmitter.js deleted file mode 100644 index 3450b4ac6..000000000 --- a/lib/react-native/EventEmitter.js +++ /dev/null @@ -1,16 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * This is a simple wrapper to unify EventEmitter implementations across platforms. - */ - -{ - const EventEmitter = require('EventEmitter'); - EventEmitter.prototype.on = EventEmitter.prototype.addListener; - module.exports = EventEmitter; -} \ No newline at end of file diff --git a/lib/react-native/FacebookUtils.js b/lib/react-native/FacebookUtils.js deleted file mode 100644 index 24ce10c01..000000000 --- a/lib/react-native/FacebookUtils.js +++ /dev/null @@ -1,229 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * -weak - */ - -import parseDate from './parseDate'; -import ParseUser from './ParseUser'; - -var PUBLIC_KEY = "*"; - -var initialized = false; -var requestedPermissions; -var initOptions; -var provider = { - authenticate(options) { - if (typeof FB === 'undefined') { - options.error(this, 'Facebook SDK not found.'); - } - FB.login(response => { - if (response.authResponse) { - if (options.success) { - options.success(this, { - id: response.authResponse.userID, - access_token: response.authResponse.accessToken, - expiration_date: new Date(response.authResponse.expiresIn * 1000 + new Date().getTime()).toJSON() - }); - } - } else { - if (options.error) { - options.error(this, response); - } - } - }, { - scope: requestedPermissions - }); - }, - - restoreAuthentication(authData) { - if (authData) { - var expiration = parseDate(authData.expiration_date); - var expiresIn = expiration ? (expiration.getTime() - new Date().getTime()) / 1000 : 0; - - var authResponse = { - userID: authData.id, - accessToken: authData.access_token, - expiresIn: expiresIn - }; - var newOptions = {}; - if (initOptions) { - for (var key in initOptions) { - newOptions[key] = initOptions[key]; - } - } - newOptions.authResponse = authResponse; - - // Suppress checks for login status from the browser. - newOptions.status = false; - - // If the user doesn't match the one known by the FB SDK, log out. - // Most of the time, the users will match -- it's only in cases where - // the FB SDK knows of a different user than the one being restored - // from a Parse User that logged in with username/password. - var existingResponse = FB.getAuthResponse(); - if (existingResponse && existingResponse.userID !== authResponse.userID) { - FB.logout(); - } - - FB.init(newOptions); - } - return true; - }, - - getAuthType() { - return 'facebook'; - }, - - deauthenticate() { - this.restoreAuthentication(null); - } -}; - -/** - * Provides a set of utilities for using Parse with Facebook. - * @class Parse.FacebookUtils - * @static - */ -var FacebookUtils = { - /** - * Initializes Parse Facebook integration. Call this function after you - * have loaded the Facebook Javascript SDK with the same parameters - * as you would pass to - * - * FB.init(). Parse.FacebookUtils will invoke FB.init() for you - * with these arguments. - * - * @method init - * @param {Object} options Facebook options argument as described here: - * - * FB.init(). The status flag will be coerced to 'false' because it - * interferes with Parse Facebook integration. Call FB.getLoginStatus() - * explicitly if this behavior is required by your application. - */ - init(options) { - if (typeof FB === 'undefined') { - throw new Error('The Facebook JavaScript SDK must be loaded before calling init.'); - } - initOptions = {}; - if (options) { - for (var key in options) { - initOptions[key] = options[key]; - } - } - if (initOptions.status && typeof console !== 'undefined') { - var warn = console.warn || console.log || function () {}; - warn.call(console, 'The "status" flag passed into' + ' FB.init, when set to true, can interfere with Parse Facebook' + ' integration, so it has been suppressed. Please call' + ' FB.getLoginStatus() explicitly if you require this behavior.'); - } - initOptions.status = false; - FB.init(initOptions); - ParseUser._registerAuthenticationProvider(provider); - initialized = true; - }, - - /** - * Gets whether the user has their account linked to Facebook. - * - * @method isLinked - * @param {Parse.User} user User to check for a facebook link. - * The user must be logged in on this device. - * @return {Boolean} true if the user has their account - * linked to Facebook. - */ - isLinked(user) { - return user._isLinked('facebook'); - }, - - /** - * Logs in a user using Facebook. This method delegates to the Facebook - * SDK to authenticate the user, and then automatically logs in (or - * creates, in the case where it is a new user) a Parse.User. - * - * @method logIn - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - logIn(permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling logIn.'); - } - requestedPermissions = permissions; - return ParseUser._logInWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return ParseUser._logInWith('facebook', newOptions); - } - }, - - /** - * Links Facebook to an existing PFUser. This method delegates to the - * Facebook SDK to authenticate the user, and then automatically links - * the account to the Parse.User. - * - * @method link - * @param {Parse.User} user User to link to Facebook. This must be the - * current user. - * @param {String, Object} permissions The permissions required for Facebook - * log in. This is a comma-separated string of permissions. - * Alternatively, supply a Facebook authData object as described in our - * REST API docs if you want to handle getting facebook auth tokens - * yourself. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - link(user, permissions, options) { - if (!permissions || typeof permissions === 'string') { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling link.'); - } - requestedPermissions = permissions; - return user._linkWith('facebook', options); - } else { - var newOptions = {}; - if (options) { - for (var key in options) { - newOptions[key] = options[key]; - } - } - newOptions.authData = permissions; - return user._linkWith('facebook', newOptions); - } - }, - - /** - * Unlinks the Parse.User from a Facebook account. - * - * @method unlink - * @param {Parse.User} user User to unlink from Facebook. This must be the - * current user. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - unlink: function (user, options) { - if (!initialized) { - throw new Error('You must initialize FacebookUtils before calling unlink.'); - } - return user._unlinkFrom('facebook', options); - } -}; - -export default FacebookUtils; \ No newline at end of file diff --git a/lib/react-native/InstallationController.js b/lib/react-native/InstallationController.js deleted file mode 100644 index 75aad6d0b..000000000 --- a/lib/react-native/InstallationController.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import ParsePromise from './ParsePromise'; -import Storage from './Storage'; - -var iidCache = null; - -function hexOctet() { - return Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1); -} - -function generateId() { - return hexOctet() + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + '-' + hexOctet() + hexOctet() + hexOctet(); -} - -var InstallationController = { - currentInstallationId() { - if (typeof iidCache === 'string') { - return ParsePromise.as(iidCache); - } - var path = Storage.generatePath('installationId'); - return Storage.getItemAsync(path).then(iid => { - if (!iid) { - iid = generateId(); - return Storage.setItemAsync(path, iid).then(() => { - iidCache = iid; - return iid; - }); - } - iidCache = iid; - return iid; - }); - }, - - _clearCache() { - iidCache = null; - }, - - _setInstallationIdCache(iid) { - iidCache = iid; - } -}; - -module.exports = InstallationController; \ No newline at end of file diff --git a/lib/react-native/LiveQueryClient.js b/lib/react-native/LiveQueryClient.js deleted file mode 100644 index 0af495cb4..000000000 --- a/lib/react-native/LiveQueryClient.js +++ /dev/null @@ -1,430 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -import EventEmitter from './EventEmitter'; -import ParsePromise from './ParsePromise'; -import ParseObject from './ParseObject'; -import LiveQuerySubscription from './LiveQuerySubscription'; - -// The LiveQuery client inner state -const CLIENT_STATE = { - INITIALIZED: 'initialized', - CONNECTING: 'connecting', - CONNECTED: 'connected', - CLOSED: 'closed', - RECONNECTING: 'reconnecting', - DISCONNECTED: 'disconnected' -}; - -// The event type the LiveQuery client should sent to server -const OP_TYPES = { - CONNECT: 'connect', - SUBSCRIBE: 'subscribe', - UNSUBSCRIBE: 'unsubscribe', - ERROR: 'error' -}; - -// The event we get back from LiveQuery server -const OP_EVENTS = { - CONNECTED: 'connected', - SUBSCRIBED: 'subscribed', - UNSUBSCRIBED: 'unsubscribed', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -// The event the LiveQuery client should emit -const CLIENT_EMMITER_TYPES = { - CLOSE: 'close', - ERROR: 'error', - OPEN: 'open' -}; - -// The event the LiveQuery subscription should emit -const SUBSCRIPTION_EMMITER_TYPES = { - OPEN: 'open', - CLOSE: 'close', - ERROR: 'error', - CREATE: 'create', - UPDATE: 'update', - ENTER: 'enter', - LEAVE: 'leave', - DELETE: 'delete' -}; - -let generateInterval = k => { - return Math.random() * Math.min(30, Math.pow(2, k) - 1) * 1000; -}; - -/** - * Creates a new LiveQueryClient. - * Extends events.EventEmitter - * cloud functions. - * - * A wrapper of a standard WebSocket client. We add several useful methods to - * help you connect/disconnect to LiveQueryServer, subscribe/unsubscribe a ParseQuery easily. - * - * javascriptKey and masterKey are used for verifying the LiveQueryClient when it tries - * to connect to the LiveQuery server - * - * @class Parse.LiveQueryClient - * @constructor - * @param {Object} options - * @param {string} options.applicationId - applicationId of your Parse app - * @param {string} options.serverURL - the URL of your LiveQuery server - * @param {string} options.javascriptKey (optional) - * @param {string} options.masterKey (optional) Your Parse Master Key. (Node.js only!) - * @param {string} options.sessionToken (optional) - * - * - * We expose three events to help you monitor the status of the LiveQueryClient. - * - *
                              - * let Parse = require('parse/node');
                              - * let LiveQueryClient = Parse.LiveQueryClient;
                              - * let client = new LiveQueryClient({
                              - *   applicationId: '',
                              - *   serverURL: '',
                              - *   javascriptKey: '',
                              - *   masterKey: ''
                              - *  });
                              - * 
                              - * - * Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - *
                              - * client.on('open', () => {
                              - * 
                              - * });
                              - * - * Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - *
                              - * client.on('close', () => {
                              - * 
                              - * });
                              - * - * Error - When some network error or LiveQuery server error happens, you'll get this event. - *
                              - * client.on('error', (error) => {
                              - * 
                              - * });
                              - * - * - */ -export default class LiveQueryClient extends EventEmitter { - - constructor({ - applicationId, - serverURL, - javascriptKey, - masterKey, - sessionToken - }) { - super(); - - if (!serverURL || serverURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - this.reconnectHandle = null; - this.attempts = 1;; - this.id = 0; - this.requestId = 1; - this.serverURL = serverURL; - this.applicationId = applicationId; - this.javascriptKey = javascriptKey; - this.masterKey = masterKey; - this.sessionToken = sessionToken; - this.connectPromise = new ParsePromise(); - this.subscriptions = new Map(); - this.state = CLIENT_STATE.INITIALIZED; - } - - shouldOpen() { - return this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED; - } - - /** - * Subscribes to a ParseQuery - * - * If you provide the sessionToken, when the LiveQuery server gets ParseObject's - * updates from parse server, it'll try to check whether the sessionToken fulfills - * the ParseObject's ACL. The LiveQuery server will only send updates to clients whose - * sessionToken is fit for the ParseObject's ACL. You can check the LiveQuery protocol - * here for more details. The subscription you get is the same subscription you get - * from our Standard API. - * - * @method subscribe - * @param {Object} query - the ParseQuery you want to subscribe to - * @param {string} sessionToken (optional) - * @return {Object} subscription - */ - subscribe(query, sessionToken) { - if (!query) { - return; - } - let where = query.toJSON().where; - let className = query.className; - let subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId: this.requestId, - query: { - className, - where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - let subscription = new LiveQuerySubscription(this.requestId, query, sessionToken); - this.subscriptions.set(this.requestId, subscription); - this.requestId += 1; - this.connectPromise.then(() => { - this.socket.send(JSON.stringify(subscribeRequest)); - }); - - // adding listener so process does not crash - // best practice is for developer to register their own listener - subscription.on('error', () => {}); - - return subscription; - } - - /** - * After calling unsubscribe you'll stop receiving events from the subscription object. - * - * @method unsubscribe - * @param {Object} subscription - subscription you would like to unsubscribe from. - */ - unsubscribe(subscription) { - if (!subscription) { - return; - } - - this.subscriptions.delete(subscription.id); - let unsubscribeRequest = { - op: OP_TYPES.UNSUBSCRIBE, - requestId: subscription.id - }; - this.connectPromise.then(() => { - this.socket.send(JSON.stringify(unsubscribeRequest)); - }); - } - - /** - * After open is called, the LiveQueryClient will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ - open() { - let WebSocketImplementation = this._getWebSocketImplementation(); - if (!WebSocketImplementation) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, 'Can not find WebSocket implementation'); - return; - } - - if (this.state !== CLIENT_STATE.RECONNECTING) { - this.state = CLIENT_STATE.CONNECTING; - } - - // Get WebSocket implementation - this.socket = new WebSocketImplementation(this.serverURL); - - // Bind WebSocket callbacks - this.socket.onopen = () => { - this._handleWebSocketOpen(); - }; - - this.socket.onmessage = event => { - this._handleWebSocketMessage(event); - }; - - this.socket.onclose = () => { - this._handleWebSocketClose(); - }; - - this.socket.onerror = error => { - this._handleWebSocketError(error); - }; - } - - resubscribe() { - this.subscriptions.forEach((subscription, requestId) => { - let query = subscription.query; - let where = query.toJSON().where; - let className = query.className; - let sessionToken = subscription.sessionToken; - let subscribeRequest = { - op: OP_TYPES.SUBSCRIBE, - requestId, - query: { - className, - where - } - }; - - if (sessionToken) { - subscribeRequest.sessionToken = sessionToken; - } - - this.connectPromise.then(() => { - this.socket.send(JSON.stringify(subscribeRequest)); - }); - }); - } - - /** - * This method will close the WebSocket connection to this LiveQueryClient, - * cancel the auto reconnect and unsubscribe all subscriptions based on it. - * - * @method close - */ - close() { - if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.DISCONNECTED; - this.socket.close(); - // Notify each subscription about the close - for (let subscription of this.subscriptions.values()) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - this._handleReset(); - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - } - - _getWebSocketImplementation() { - return WebSocket; - } - - // ensure we start with valid state if connect is called again after close - _handleReset() { - this.attempts = 1;; - this.id = 0; - this.requestId = 1; - this.connectPromise = new ParsePromise(); - this.subscriptions = new Map(); - } - - _handleWebSocketOpen() { - this.attempts = 1; - let connectRequest = { - op: OP_TYPES.CONNECT, - applicationId: this.applicationId, - javascriptKey: this.javascriptKey, - masterKey: this.masterKey, - sessionToken: this.sessionToken - }; - this.socket.send(JSON.stringify(connectRequest)); - } - - _handleWebSocketMessage(event) { - let data = event.data; - if (typeof data === 'string') { - data = JSON.parse(data); - } - let subscription = null; - if (data.requestId) { - subscription = this.subscriptions.get(data.requestId); - } - switch (data.op) { - case OP_EVENTS.CONNECTED: - if (this.state === CLIENT_STATE.RECONNECTING) { - this.resubscribe(); - } - this.emit(CLIENT_EMMITER_TYPES.OPEN); - this.id = data.clientId; - this.connectPromise.resolve(); - this.state = CLIENT_STATE.CONNECTED; - break; - case OP_EVENTS.SUBSCRIBED: - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN); - } - break; - case OP_EVENTS.ERROR: - if (data.requestId) { - if (subscription) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error); - } - } else { - this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error); - } - break; - case OP_EVENTS.UNSUBSCRIBED: - // We have already deleted subscription in unsubscribe(), do nothing here - break; - default: - // create, update, enter, leave, delete cases - let className = data.object.className; - // Delete the extrea __type and className fields during transfer to full JSON - delete data.object.__type; - delete data.object.className; - let parseObject = new ParseObject(className); - parseObject._finishFetch(data.object); - if (!subscription) { - break; - } - subscription.emit(data.op, parseObject); - } - } - - _handleWebSocketClose() { - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - this.state = CLIENT_STATE.CLOSED; - this.emit(CLIENT_EMMITER_TYPES.CLOSE); - // Notify each subscription about the close - for (let subscription of this.subscriptions.values()) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.CLOSE); - } - this._handleReconnect(); - } - - _handleWebSocketError(error) { - this.emit(CLIENT_EMMITER_TYPES.ERROR, error); - for (let subscription of this.subscriptions.values()) { - subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR); - } - this._handleReconnect(); - } - - _handleReconnect() { - // if closed or currently reconnecting we stop attempting to reconnect - if (this.state === CLIENT_STATE.DISCONNECTED) { - return; - } - - this.state = CLIENT_STATE.RECONNECTING; - let time = generateInterval(this.attempts); - - // handle case when both close/error occur at frequent rates we ensure we do not reconnect unnecessarily. - // we're unable to distinguish different between close/error when we're unable to reconnect therefore - // we try to reonnect in both cases - // server side ws and browser WebSocket behave differently in when close/error get triggered - - if (this.reconnectHandle) { - clearTimeout(this.reconnectHandle); - } - - this.reconnectHandle = setTimeout((() => { - this.attempts++; - this.connectPromise = new ParsePromise(); - this.open(); - }).bind(this), time); - } -} \ No newline at end of file diff --git a/lib/react-native/LiveQuerySubscription.js b/lib/react-native/LiveQuerySubscription.js deleted file mode 100644 index 4f19b2b6e..000000000 --- a/lib/react-native/LiveQuerySubscription.js +++ /dev/null @@ -1,112 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - */ - -import EventEmitter from './EventEmitter'; -import CoreManager from './CoreManager'; - -/** - * Creates a new LiveQuery Subscription. - * Extends events.EventEmitter - * cloud functions. - * - * @constructor - * @param {string} id - subscription id - * @param {string} query - query to subscribe to - * @param {string} sessionToken - optional session token - * - *

                              Open Event - When you call query.subscribe(), we send a subscribe request to - * the LiveQuery server, when we get the confirmation from the LiveQuery server, - * this event will be emitted. When the client loses WebSocket connection to the - * LiveQuery server, we will try to auto reconnect the LiveQuery server. If we - * reconnect the LiveQuery server and successfully resubscribe the ParseQuery, - * you'll also get this event. - * - *

                              - * subscription.on('open', () => {
                              - * 
                              - * });

                              - * - *

                              Create Event - When a new ParseObject is created and it fulfills the ParseQuery you subscribe, - * you'll get this event. The object is the ParseObject which is created. - * - *

                              - * subscription.on('create', (object) => {
                              - * 
                              - * });

                              - * - *

                              Update Event - When an existing ParseObject which fulfills the ParseQuery you subscribe - * is updated (The ParseObject fulfills the ParseQuery before and after changes), - * you'll get this event. The object is the ParseObject which is updated. - * Its content is the latest value of the ParseObject. - * - *

                              - * subscription.on('update', (object) => {
                              - * 
                              - * });

                              - * - *

                              Enter Event - When an existing ParseObject's old value doesn't fulfill the ParseQuery - * but its new value fulfills the ParseQuery, you'll get this event. The object is the - * ParseObject which enters the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                              - * subscription.on('enter', (object) => {
                              - * 
                              - * });

                              - * - * - *

                              Update Event - When an existing ParseObject's old value fulfills the ParseQuery but its new value - * doesn't fulfill the ParseQuery, you'll get this event. The object is the ParseObject - * which leaves the ParseQuery. Its content is the latest value of the ParseObject. - * - *

                              - * subscription.on('leave', (object) => {
                              - * 
                              - * });

                              - * - * - *

                              Delete Event - When an existing ParseObject which fulfills the ParseQuery is deleted, you'll - * get this event. The object is the ParseObject which is deleted. - * - *

                              - * subscription.on('delete', (object) => {
                              - * 
                              - * });

                              - * - * - *

                              Close Event - When the client loses the WebSocket connection to the LiveQuery - * server and we stop receiving events, you'll get this event. - * - *

                              - * subscription.on('close', () => {
                              - * 
                              - * });

                              - * - * - */ -export default class Subscription extends EventEmitter { - constructor(id, query, sessionToken) { - super(); - this.id = id; - this.query = query; - this.sessionToken = sessionToken; - } - - /** - * @method unsubscribe - */ - unsubscribe() { - let _this = this; - CoreManager.getLiveQueryController().getDefaultLiveQueryClient().then(liveQueryClient => { - liveQueryClient.unsubscribe(_this); - _this.emit('close'); - this.resolve(); - }); - } -} \ No newline at end of file diff --git a/lib/react-native/ObjectStateMutations.js b/lib/react-native/ObjectStateMutations.js deleted file mode 100644 index 349dd150b..000000000 --- a/lib/react-native/ObjectStateMutations.js +++ /dev/null @@ -1,121 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import encode from './encode'; -import ParseFile from './ParseFile'; -import ParseObject from './ParseObject'; -import ParsePromise from './ParsePromise'; -import ParseRelation from './ParseRelation'; -import TaskQueue from './TaskQueue'; -import { RelationOp } from './ParseOp'; - -export function defaultState() { - return { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new TaskQueue(), - existed: false - }; -} - -export function setServerData(serverData, attributes) { - for (let attr in attributes) { - if (typeof attributes[attr] !== 'undefined') { - serverData[attr] = attributes[attr]; - } else { - delete serverData[attr]; - } - } -} - -export function setPendingOp(pendingOps, attr, op) { - let last = pendingOps.length - 1; - if (op) { - pendingOps[last][attr] = op; - } else { - delete pendingOps[last][attr]; - } -} - -export function pushPendingState(pendingOps) { - pendingOps.push({}); -} - -export function popPendingState(pendingOps) { - let first = pendingOps.shift(); - if (!pendingOps.length) { - pendingOps[0] = {}; - } - return first; -} - -export function mergeFirstPendingState(pendingOps) { - let first = popPendingState(pendingOps); - let next = pendingOps[0]; - for (let attr in first) { - if (next[attr] && first[attr]) { - let merged = next[attr].mergeWith(first[attr]); - if (merged) { - next[attr] = merged; - } - } else { - next[attr] = first[attr]; - } - } -} - -export function estimateAttribute(serverData, pendingOps, className, id, attr) { - let value = serverData[attr]; - for (let i = 0; i < pendingOps.length; i++) { - if (pendingOps[i][attr]) { - if (pendingOps[i][attr] instanceof RelationOp) { - if (id) { - value = pendingOps[i][attr].applyTo(value, { className: className, id: id }, attr); - } - } else { - value = pendingOps[i][attr].applyTo(value); - } - } - } - return value; -} - -export function estimateAttributes(serverData, pendingOps, className, id) { - let data = {}; - - for (var attr in serverData) { - data[attr] = serverData[attr]; - } - for (let i = 0; i < pendingOps.length; i++) { - for (attr in pendingOps[i]) { - if (pendingOps[i][attr] instanceof RelationOp) { - if (id) { - data[attr] = pendingOps[i][attr].applyTo(data[attr], { className: className, id: id }, attr); - } - } else { - data[attr] = pendingOps[i][attr].applyTo(data[attr]); - } - } - } - return data; -} - -export function commitServerChanges(serverData, objectCache, changes) { - for (let attr in changes) { - let val = changes[attr]; - serverData[attr] = val; - if (val && typeof val === 'object' && !(val instanceof ParseObject) && !(val instanceof ParseFile) && !(val instanceof ParseRelation)) { - let json = encode(val, false, true); - objectCache[attr] = JSON.stringify(json); - } - } -} \ No newline at end of file diff --git a/lib/react-native/Parse.js b/lib/react-native/Parse.js deleted file mode 100644 index b95835026..000000000 --- a/lib/react-native/Parse.js +++ /dev/null @@ -1,141 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -import decode from './decode'; -import encode from './encode'; -import CoreManager from './CoreManager'; -import InstallationController from './InstallationController'; -import * as ParseOp from './ParseOp'; -import RESTController from './RESTController'; - -/** - * Contains all Parse API classes and functions. - * @class Parse - * @static - */ -var Parse = { - /** - * Call this method first to set up your authentication tokens for Parse. - * You can get your keys from the Data Browser on parse.com. - * @method initialize - * @param {String} applicationId Your Parse Application ID. - * @param {String} javaScriptKey (optional) Your Parse JavaScript Key (Not needed for parse-server) - * @param {String} masterKey (optional) Your Parse Master Key. (Node.js only!) - * @static - */ - initialize(applicationId, javaScriptKey) { - Parse._initialize(applicationId, javaScriptKey); - }, - - _initialize(applicationId, javaScriptKey, masterKey) { - CoreManager.set('APPLICATION_ID', applicationId); - CoreManager.set('JAVASCRIPT_KEY', javaScriptKey); - CoreManager.set('MASTER_KEY', masterKey); - CoreManager.set('USE_MASTER_KEY', false); - } -}; - -/** These legacy setters may eventually be deprecated **/ -Object.defineProperty(Parse, 'applicationId', { - get() { - return CoreManager.get('APPLICATION_ID'); - }, - set(value) { - CoreManager.set('APPLICATION_ID', value); - } -}); -Object.defineProperty(Parse, 'javaScriptKey', { - get() { - return CoreManager.get('JAVASCRIPT_KEY'); - }, - set(value) { - CoreManager.set('JAVASCRIPT_KEY', value); - } -}); -Object.defineProperty(Parse, 'masterKey', { - get() { - return CoreManager.get('MASTER_KEY'); - }, - set(value) { - CoreManager.set('MASTER_KEY', value); - } -}); -Object.defineProperty(Parse, 'serverURL', { - get() { - return CoreManager.get('SERVER_URL'); - }, - set(value) { - CoreManager.set('SERVER_URL', value); - } -}); -Object.defineProperty(Parse, 'liveQueryServerURL', { - get() { - return CoreManager.get('LIVEQUERY_SERVER_URL'); - }, - set(value) { - CoreManager.set('LIVEQUERY_SERVER_URL', value); - } -}); -/** End setters **/ - -Parse.ACL = require('./ParseACL').default; -Parse.Analytics = require('./Analytics'); -Parse.Cloud = require('./Cloud'); -Parse.CoreManager = require('./CoreManager'); -Parse.Config = require('./ParseConfig').default; -Parse.Error = require('./ParseError').default; -Parse.FacebookUtils = require('./FacebookUtils').default; -Parse.File = require('./ParseFile').default; -Parse.GeoPoint = require('./ParseGeoPoint').default; -Parse.Installation = require('./ParseInstallation').default; -Parse.Object = require('./ParseObject').default; -Parse.Op = { - Set: ParseOp.SetOp, - Unset: ParseOp.UnsetOp, - Increment: ParseOp.IncrementOp, - Add: ParseOp.AddOp, - Remove: ParseOp.RemoveOp, - AddUnique: ParseOp.AddUniqueOp, - Relation: ParseOp.RelationOp -}; -Parse.Promise = require('./ParsePromise').default; -Parse.Push = require('./Push'); -Parse.Query = require('./ParseQuery').default; -Parse.Relation = require('./ParseRelation').default; -Parse.Role = require('./ParseRole').default; -Parse.Session = require('./ParseSession').default; -Parse.Storage = require('./Storage'); -Parse.User = require('./ParseUser').default; -Parse.LiveQuery = require('./ParseLiveQuery').default; -Parse.LiveQueryClient = require('./LiveQueryClient').default; - -Parse._request = function (...args) { - return CoreManager.getRESTController().request.apply(null, args); -}; -Parse._ajax = function (...args) { - return CoreManager.getRESTController().ajax.apply(null, args); -}; -// We attempt to match the signatures of the legacy versions of these methods -Parse._decode = function (_, value) { - return decode(value); -}; -Parse._encode = function (value, _, disallowObjects) { - return encode(value, disallowObjects); -}; -Parse._getInstallationId = function () { - return CoreManager.getInstallationController().currentInstallationId(); -}; - -CoreManager.setInstallationController(InstallationController); -CoreManager.setRESTController(RESTController); - -// For legacy requires, of the form `var Parse = require('parse').Parse` -Parse.Parse = Parse; - -module.exports = Parse; \ No newline at end of file diff --git a/lib/react-native/ParseACL.js b/lib/react-native/ParseACL.js deleted file mode 100644 index 2c28c6fa6..000000000 --- a/lib/react-native/ParseACL.js +++ /dev/null @@ -1,325 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseRole from './ParseRole'; -import ParseUser from './ParseUser'; - -var PUBLIC_KEY = '*'; - -/** - * Creates a new ACL. - * If no argument is given, the ACL has no permissions for anyone. - * If the argument is a Parse.User, the ACL will have read and write - * permission for only that user. - * If the argument is any other JSON object, that object will be interpretted - * as a serialized ACL created with toJSON(). - * @class Parse.ACL - * @constructor - * - *

                              An ACL, or Access Control List can be added to any - * Parse.Object to restrict access to only a subset of users - * of your application.

                              - */ -export default class ParseACL { - - constructor(arg1) { - this.permissionsById = {}; - if (arg1 && typeof arg1 === 'object') { - if (arg1 instanceof ParseUser) { - this.setReadAccess(arg1, true); - this.setWriteAccess(arg1, true); - } else { - for (var userId in arg1) { - var accessList = arg1[userId]; - if (typeof userId !== 'string') { - throw new TypeError('Tried to create an ACL with an invalid user id.'); - } - this.permissionsById[userId] = {}; - for (var permission in accessList) { - var allowed = accessList[permission]; - if (permission !== 'read' && permission !== 'write') { - throw new TypeError('Tried to create an ACL with an invalid permission type.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('Tried to create an ACL with an invalid permission value.'); - } - this.permissionsById[userId][permission] = allowed; - } - } - } - } else if (typeof arg1 === 'function') { - throw new TypeError('ParseACL constructed with a function. Did you forget ()?'); - } - } - - /** - * Returns a JSON-encoded version of the ACL. - * @method toJSON - * @return {Object} - */ - toJSON() { - var permissions = {}; - for (var p in this.permissionsById) { - permissions[p] = this.permissionsById[p]; - } - return permissions; - } - - /** - * Returns whether this ACL is equal to another object - * @method equals - * @param other The other object to compare to - * @return {Boolean} - */ - equals(other) { - if (!(other instanceof ParseACL)) { - return false; - } - var users = Object.keys(this.permissionsById); - var otherUsers = Object.keys(other.permissionsById); - if (users.length !== otherUsers.length) { - return false; - } - for (var u in this.permissionsById) { - if (!other.permissionsById[u]) { - return false; - } - if (this.permissionsById[u].read !== other.permissionsById[u].read) { - return false; - } - if (this.permissionsById[u].write !== other.permissionsById[u].write) { - return false; - } - } - return true; - } - - _setAccess(accessType, userId, allowed) { - if (userId instanceof ParseUser) { - userId = userId.id; - } else if (userId instanceof ParseRole) { - const name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - if (typeof userId !== 'string') { - throw new TypeError('userId must be a string.'); - } - if (typeof allowed !== 'boolean') { - throw new TypeError('allowed must be either true or false.'); - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - if (!allowed) { - // The user already doesn't have this permission, so no action is needed - return; - } else { - permissions = {}; - this.permissionsById[userId] = permissions; - } - } - - if (allowed) { - this.permissionsById[userId][accessType] = true; - } else { - delete permissions[accessType]; - if (Object.keys(permissions).length === 0) { - delete this.permissionsById[userId]; - } - } - } - - _getAccess(accessType, userId) { - if (userId instanceof ParseUser) { - userId = userId.id; - if (!userId) { - throw new Error('Cannot get access for a ParseUser without an ID'); - } - } else if (userId instanceof ParseRole) { - const name = userId.getName(); - if (!name) { - throw new TypeError('Role must have a name'); - } - userId = 'role:' + name; - } - var permissions = this.permissionsById[userId]; - if (!permissions) { - return false; - } - return !!permissions[accessType]; - } - - /** - * Sets whether the given user is allowed to read this object. - * @method setReadAccess - * @param userId An instance of Parse.User or its objectId. - * @param {Boolean} allowed Whether that user should have read access. - */ - setReadAccess(userId, allowed) { - this._setAccess('read', userId, allowed); - } - - /** - * Get whether the given user id is *explicitly* allowed to read this object. - * Even if this returns false, the user may still be able to access it if - * getPublicReadAccess returns true or a role that the user belongs to has - * write access. - * @method getReadAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - getReadAccess(userId) { - return this._getAccess('read', userId); - } - - /** - * Sets whether the given user id is allowed to write this object. - * @method setWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role.. - * @param {Boolean} allowed Whether that user should have write access. - */ - setWriteAccess(userId, allowed) { - this._setAccess('write', userId, allowed); - } - - /** - * Gets whether the given user id is *explicitly* allowed to write this object. - * Even if this returns false, the user may still be able to write it if - * getPublicWriteAccess returns true or a role that the user belongs to has - * write access. - * @method getWriteAccess - * @param userId An instance of Parse.User or its objectId, or a Parse.Role. - * @return {Boolean} - */ - getWriteAccess(userId) { - return this._getAccess('write', userId); - } - - /** - * Sets whether the public is allowed to read this object. - * @method setPublicReadAccess - * @param {Boolean} allowed - */ - setPublicReadAccess(allowed) { - this.setReadAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to read this object. - * @method getPublicReadAccess - * @return {Boolean} - */ - getPublicReadAccess() { - return this.getReadAccess(PUBLIC_KEY); - } - - /** - * Sets whether the public is allowed to write this object. - * @method setPublicWriteAccess - * @param {Boolean} allowed - */ - setPublicWriteAccess(allowed) { - this.setWriteAccess(PUBLIC_KEY, allowed); - } - - /** - * Gets whether the public is allowed to write this object. - * @method getPublicWriteAccess - * @return {Boolean} - */ - getPublicWriteAccess() { - return this.getWriteAccess(PUBLIC_KEY); - } - - /** - * Gets whether users belonging to the given role are allowed - * to read this object. Even if this returns false, the role may - * still be able to write it if a parent role has read access. - * - * @method getRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has read access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - getRoleReadAccess(role) { - if (role instanceof ParseRole) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getReadAccess('role:' + role); - } - - /** - * Gets whether users belonging to the given role are allowed - * to write this object. Even if this returns false, the role may - * still be able to write it if a parent role has write access. - * - * @method getRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @return {Boolean} true if the role has write access. false otherwise. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - getRoleWriteAccess(role) { - if (role instanceof ParseRole) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - return this.getWriteAccess('role:' + role); - } - - /** - * Sets whether users belonging to the given role are allowed - * to read this object. - * - * @method setRoleReadAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can read this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - setRoleReadAccess(role, allowed) { - if (role instanceof ParseRole) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setReadAccess('role:' + role, allowed); - } - - /** - * Sets whether users belonging to the given role are allowed - * to write this object. - * - * @method setRoleWriteAccess - * @param role The name of the role, or a Parse.Role object. - * @param {Boolean} allowed Whether the given role can write this object. - * @throws {TypeError} If role is neither a Parse.Role nor a String. - */ - setRoleWriteAccess(role, allowed) { - if (role instanceof ParseRole) { - // Normalize to the String name - role = role.getName(); - } - if (typeof role !== 'string') { - throw new TypeError('role must be a ParseRole or a String'); - } - this.setWriteAccess('role:' + role, allowed); - } -} \ No newline at end of file diff --git a/lib/react-native/ParseConfig.js b/lib/react-native/ParseConfig.js deleted file mode 100644 index ce6cbdb45..000000000 --- a/lib/react-native/ParseConfig.js +++ /dev/null @@ -1,168 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import decode from './decode'; -import encode from './encode'; -import escape from './escape'; -import ParseError from './ParseError'; -import ParsePromise from './ParsePromise'; -import Storage from './Storage'; - -/** - * Parse.Config is a local representation of configuration data that - * can be set from the Parse dashboard. - * - * @class Parse.Config - * @constructor - */ - -export default class ParseConfig { - - constructor() { - this.attributes = {}; - this._escapedAttributes = {}; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The name of an attribute. - */ - get(attr) { - return this.attributes[attr]; - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The name of an attribute. - */ - escape(attr) { - var html = this._escapedAttributes[attr]; - if (html) { - return html; - } - var val = this.attributes[attr]; - var escaped = ''; - if (val != null) { - escaped = escape(val.toString()); - } - this._escapedAttributes[attr] = escaped; - return escaped; - } - - /** - * Retrieves the most recently-fetched configuration object, either from - * memory or from local storage if necessary. - * - * @method current - * @static - * @return {Config} The most recently-fetched Parse.Config if it - * exists, else an empty Parse.Config. - */ - static current() { - var controller = CoreManager.getConfigController(); - return controller.current(); - } - - /** - * Gets a new configuration object from the server. - * @method get - * @static - * @param {Object} options A Backbone-style options object. - * Valid options are:
                                - *
                              • success: Function to call when the get completes successfully. - *
                              • error: Function to call when the get fails. - *
                              - * @return {Parse.Promise} A promise that is resolved with a newly-created - * configuration object when the get completes. - */ - static get(options) { - options = options || {}; - - var controller = CoreManager.getConfigController(); - return controller.get()._thenRunCallbacks(options); - } -} - -var currentConfig = null; - -var CURRENT_CONFIG_KEY = 'currentConfig'; - -function decodePayload(data) { - try { - var json = JSON.parse(data); - if (json && typeof json === 'object') { - return decode(json); - } - } catch (e) { - return null; - } -} - -var DefaultController = { - current() { - if (currentConfig) { - return currentConfig; - } - - var config = new ParseConfig(); - var storagePath = Storage.generatePath(CURRENT_CONFIG_KEY); - var configData; - if (!Storage.async()) { - configData = Storage.getItem(storagePath); - - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - } - // Return a promise for async storage controllers - return Storage.getItemAsync(storagePath).then(configData => { - if (configData) { - var attributes = decodePayload(configData); - if (attributes) { - config.attributes = attributes; - currentConfig = config; - } - } - return config; - }); - }, - - get() { - var RESTController = CoreManager.getRESTController(); - - return RESTController.request('GET', 'config', {}, {}).then(response => { - if (!response || !response.params) { - var error = new ParseError(ParseError.INVALID_JSON, 'Config JSON response invalid.'); - return ParsePromise.error(error); - } - - var config = new ParseConfig(); - config.attributes = {}; - for (var attr in response.params) { - config.attributes[attr] = decode(response.params[attr]); - } - currentConfig = config; - return Storage.setItemAsync(Storage.generatePath(CURRENT_CONFIG_KEY), JSON.stringify(response.params)).then(() => { - return config; - }); - }); - } -}; - -CoreManager.setConfigController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseError.js b/lib/react-native/ParseError.js deleted file mode 100644 index a5bb24bc7..000000000 --- a/lib/react-native/ParseError.js +++ /dev/null @@ -1,491 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -/** - * Constructs a new Parse.Error object with the given code and message. - * @class Parse.Error - * @constructor - * @param {Number} code An error code constant from Parse.Error. - * @param {String} message A detailed description of the error. - */ -export default class ParseError { - constructor(code, message) { - this.code = code; - this.message = message; - } -} - -/** - * Error code indicating some error other than those enumerated here. - * @property OTHER_CAUSE - * @static - * @final - */ -ParseError.OTHER_CAUSE = -1; - -/** - * Error code indicating that something has gone wrong with the server. - * If you get this error code, it is Parse's fault. Contact us at - * https://parse.com/help - * @property INTERNAL_SERVER_ERROR - * @static - * @final - */ -ParseError.INTERNAL_SERVER_ERROR = 1; - -/** - * Error code indicating the connection to the Parse servers failed. - * @property CONNECTION_FAILED - * @static - * @final - */ -ParseError.CONNECTION_FAILED = 100; - -/** - * Error code indicating the specified object doesn't exist. - * @property OBJECT_NOT_FOUND - * @static - * @final - */ -ParseError.OBJECT_NOT_FOUND = 101; - -/** - * Error code indicating you tried to query with a datatype that doesn't - * support it, like exact matching an array or object. - * @property INVALID_QUERY - * @static - * @final - */ -ParseError.INVALID_QUERY = 102; - -/** - * Error code indicating a missing or invalid classname. Classnames are - * case-sensitive. They must start with a letter, and a-zA-Z0-9_ are the - * only valid characters. - * @property INVALID_CLASS_NAME - * @static - * @final - */ -ParseError.INVALID_CLASS_NAME = 103; - -/** - * Error code indicating an unspecified object id. - * @property MISSING_OBJECT_ID - * @static - * @final - */ -ParseError.MISSING_OBJECT_ID = 104; - -/** - * Error code indicating an invalid key name. Keys are case-sensitive. They - * must start with a letter, and a-zA-Z0-9_ are the only valid characters. - * @property INVALID_KEY_NAME - * @static - * @final - */ -ParseError.INVALID_KEY_NAME = 105; - -/** - * Error code indicating a malformed pointer. You should not see this unless - * you have been mucking about changing internal Parse code. - * @property INVALID_POINTER - * @static - * @final - */ -ParseError.INVALID_POINTER = 106; - -/** - * Error code indicating that badly formed JSON was received upstream. This - * either indicates you have done something unusual with modifying how - * things encode to JSON, or the network is failing badly. - * @property INVALID_JSON - * @static - * @final - */ -ParseError.INVALID_JSON = 107; - -/** - * Error code indicating that the feature you tried to access is only - * available internally for testing purposes. - * @property COMMAND_UNAVAILABLE - * @static - * @final - */ -ParseError.COMMAND_UNAVAILABLE = 108; - -/** - * You must call Parse.initialize before using the Parse library. - * @property NOT_INITIALIZED - * @static - * @final - */ -ParseError.NOT_INITIALIZED = 109; - -/** - * Error code indicating that a field was set to an inconsistent type. - * @property INCORRECT_TYPE - * @static - * @final - */ -ParseError.INCORRECT_TYPE = 111; - -/** - * Error code indicating an invalid channel name. A channel name is either - * an empty string (the broadcast channel) or contains only a-zA-Z0-9_ - * characters and starts with a letter. - * @property INVALID_CHANNEL_NAME - * @static - * @final - */ -ParseError.INVALID_CHANNEL_NAME = 112; - -/** - * Error code indicating that push is misconfigured. - * @property PUSH_MISCONFIGURED - * @static - * @final - */ -ParseError.PUSH_MISCONFIGURED = 115; - -/** - * Error code indicating that the object is too large. - * @property OBJECT_TOO_LARGE - * @static - * @final - */ -ParseError.OBJECT_TOO_LARGE = 116; - -/** - * Error code indicating that the operation isn't allowed for clients. - * @property OPERATION_FORBIDDEN - * @static - * @final - */ -ParseError.OPERATION_FORBIDDEN = 119; - -/** - * Error code indicating the result was not found in the cache. - * @property CACHE_MISS - * @static - * @final - */ -ParseError.CACHE_MISS = 120; - -/** - * Error code indicating that an invalid key was used in a nested - * JSONObject. - * @property INVALID_NESTED_KEY - * @static - * @final - */ -ParseError.INVALID_NESTED_KEY = 121; - -/** - * Error code indicating that an invalid filename was used for ParseFile. - * A valid file name contains only a-zA-Z0-9_. characters and is between 1 - * and 128 characters. - * @property INVALID_FILE_NAME - * @static - * @final - */ -ParseError.INVALID_FILE_NAME = 122; - -/** - * Error code indicating an invalid ACL was provided. - * @property INVALID_ACL - * @static - * @final - */ -ParseError.INVALID_ACL = 123; - -/** - * Error code indicating that the request timed out on the server. Typically - * this indicates that the request is too expensive to run. - * @property TIMEOUT - * @static - * @final - */ -ParseError.TIMEOUT = 124; - -/** - * Error code indicating that the email address was invalid. - * @property INVALID_EMAIL_ADDRESS - * @static - * @final - */ -ParseError.INVALID_EMAIL_ADDRESS = 125; - -/** - * Error code indicating a missing content type. - * @property MISSING_CONTENT_TYPE - * @static - * @final - */ -ParseError.MISSING_CONTENT_TYPE = 126; - -/** - * Error code indicating a missing content length. - * @property MISSING_CONTENT_LENGTH - * @static - * @final - */ -ParseError.MISSING_CONTENT_LENGTH = 127; - -/** - * Error code indicating an invalid content length. - * @property INVALID_CONTENT_LENGTH - * @static - * @final - */ -ParseError.INVALID_CONTENT_LENGTH = 128; - -/** - * Error code indicating a file that was too large. - * @property FILE_TOO_LARGE - * @static - * @final - */ -ParseError.FILE_TOO_LARGE = 129; - -/** - * Error code indicating an error saving a file. - * @property FILE_SAVE_ERROR - * @static - * @final - */ -ParseError.FILE_SAVE_ERROR = 130; - -/** - * Error code indicating that a unique field was given a value that is - * already taken. - * @property DUPLICATE_VALUE - * @static - * @final - */ -ParseError.DUPLICATE_VALUE = 137; - -/** - * Error code indicating that a role's name is invalid. - * @property INVALID_ROLE_NAME - * @static - * @final - */ -ParseError.INVALID_ROLE_NAME = 139; - -/** - * Error code indicating that an application quota was exceeded. Upgrade to - * resolve. - * @property EXCEEDED_QUOTA - * @static - * @final - */ -ParseError.EXCEEDED_QUOTA = 140; - -/** - * Error code indicating that a Cloud Code script failed. - * @property SCRIPT_FAILED - * @static - * @final - */ -ParseError.SCRIPT_FAILED = 141; - -/** - * Error code indicating that a Cloud Code validation failed. - * @property VALIDATION_ERROR - * @static - * @final - */ -ParseError.VALIDATION_ERROR = 142; - -/** - * Error code indicating that invalid image data was provided. - * @property INVALID_IMAGE_DATA - * @static - * @final - */ -ParseError.INVALID_IMAGE_DATA = 143; - -/** - * Error code indicating an unsaved file. - * @property UNSAVED_FILE_ERROR - * @static - * @final - */ -ParseError.UNSAVED_FILE_ERROR = 151; - -/** - * Error code indicating an invalid push time. - * @property INVALID_PUSH_TIME_ERROR - * @static - * @final - */ -ParseError.INVALID_PUSH_TIME_ERROR = 152; - -/** - * Error code indicating an error deleting a file. - * @property FILE_DELETE_ERROR - * @static - * @final - */ -ParseError.FILE_DELETE_ERROR = 153; - -/** - * Error code indicating that the application has exceeded its request - * limit. - * @property REQUEST_LIMIT_EXCEEDED - * @static - * @final - */ -ParseError.REQUEST_LIMIT_EXCEEDED = 155; - -/** - * Error code indicating an invalid event name. - * @property INVALID_EVENT_NAME - * @static - * @final - */ -ParseError.INVALID_EVENT_NAME = 160; - -/** - * Error code indicating that the username is missing or empty. - * @property USERNAME_MISSING - * @static - * @final - */ -ParseError.USERNAME_MISSING = 200; - -/** - * Error code indicating that the password is missing or empty. - * @property PASSWORD_MISSING - * @static - * @final - */ -ParseError.PASSWORD_MISSING = 201; - -/** - * Error code indicating that the username has already been taken. - * @property USERNAME_TAKEN - * @static - * @final - */ -ParseError.USERNAME_TAKEN = 202; - -/** - * Error code indicating that the email has already been taken. - * @property EMAIL_TAKEN - * @static - * @final - */ -ParseError.EMAIL_TAKEN = 203; - -/** - * Error code indicating that the email is missing, but must be specified. - * @property EMAIL_MISSING - * @static - * @final - */ -ParseError.EMAIL_MISSING = 204; - -/** - * Error code indicating that a user with the specified email was not found. - * @property EMAIL_NOT_FOUND - * @static - * @final - */ -ParseError.EMAIL_NOT_FOUND = 205; - -/** - * Error code indicating that a user object without a valid session could - * not be altered. - * @property SESSION_MISSING - * @static - * @final - */ -ParseError.SESSION_MISSING = 206; - -/** - * Error code indicating that a user can only be created through signup. - * @property MUST_CREATE_USER_THROUGH_SIGNUP - * @static - * @final - */ -ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; - -/** - * Error code indicating that an an account being linked is already linked - * to another user. - * @property ACCOUNT_ALREADY_LINKED - * @static - * @final - */ -ParseError.ACCOUNT_ALREADY_LINKED = 208; - -/** - * Error code indicating that the current session token is invalid. - * @property INVALID_SESSION_TOKEN - * @static - * @final - */ -ParseError.INVALID_SESSION_TOKEN = 209; - -/** - * Error code indicating that a user cannot be linked to an account because - * that account's id could not be found. - * @property LINKED_ID_MISSING - * @static - * @final - */ -ParseError.LINKED_ID_MISSING = 250; - -/** - * Error code indicating that a user with a linked (e.g. Facebook) account - * has an invalid session. - * @property INVALID_LINKED_SESSION - * @static - * @final - */ -ParseError.INVALID_LINKED_SESSION = 251; - -/** - * Error code indicating that a service being linked (e.g. Facebook or - * Twitter) is unsupported. - * @property UNSUPPORTED_SERVICE - * @static - * @final - */ -ParseError.UNSUPPORTED_SERVICE = 252; - -/** - * Error code indicating that there were multiple errors. Aggregate errors - * have an "errors" property, which is an array of error objects with more - * detail about each error that occurred. - * @property AGGREGATE_ERROR - * @static - * @final - */ -ParseError.AGGREGATE_ERROR = 600; - -/** - * Error code indicating the client was unable to read an input file. - * @property FILE_READ_ERROR - * @static - * @final - */ -ParseError.FILE_READ_ERROR = 601; - -/** - * Error code indicating a real error code is unavailable because - * we had to use an XDomainRequest object to allow CORS requests in - * Internet Explorer, which strips the body from HTTP responses that have - * a non-2XX status code. - * @property X_DOMAIN_REQUEST - * @static - * @final - */ -ParseError.X_DOMAIN_REQUEST = 602; \ No newline at end of file diff --git a/lib/react-native/ParseFile.js b/lib/react-native/ParseFile.js deleted file mode 100644 index 0b1b448a8..000000000 --- a/lib/react-native/ParseFile.js +++ /dev/null @@ -1,247 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import ParsePromise from './ParsePromise'; - -var dataUriRegexp = /^data:([a-zA-Z]*\/[a-zA-Z+.-]*);(charset=[a-zA-Z0-9\-\/\s]*,)?base64,/; - -function b64Digit(number) { - if (number < 26) { - return String.fromCharCode(65 + number); - } - if (number < 52) { - return String.fromCharCode(97 + (number - 26)); - } - if (number < 62) { - return String.fromCharCode(48 + (number - 52)); - } - if (number === 62) { - return '+'; - } - if (number === 63) { - return '/'; - } - throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); -} - -/** - * A Parse.File is a local representation of a file that is saved to the Parse - * cloud. - * @class Parse.File - * @constructor - * @param name {String} The file's name. This will be prefixed by a unique - * value once the file has finished saving. The file name must begin with - * an alphanumeric character, and consist of alphanumeric characters, - * periods, spaces, underscores, or dashes. - * @param data {Array} The data for the file, as either: - * 1. an Array of byte value Numbers, or - * 2. an Object like { base64: "..." } with a base64-encoded String. - * 3. a File object selected with a file upload control. (3) only works - * in Firefox 3.6+, Safari 6.0.2+, Chrome 7+, and IE 10+. - * For example:
                              - * var fileUploadControl = $("#profilePhotoFileUpload")[0];
                              - * if (fileUploadControl.files.length > 0) {
                              - *   var file = fileUploadControl.files[0];
                              - *   var name = "photo.jpg";
                              - *   var parseFile = new Parse.File(name, file);
                              - *   parseFile.save().then(function() {
                              - *     // The file has been saved to Parse.
                              - *   }, function(error) {
                              - *     // The file either could not be read, or could not be saved to Parse.
                              - *   });
                              - * }
                              - * @param type {String} Optional Content-Type header to use for the file. If - * this is omitted, the content type will be inferred from the name's - * extension. - */ -export default class ParseFile { - - constructor(name, data, type) { - var specifiedType = type || ''; - - this._name = name; - - if (data !== undefined) { - if (Array.isArray(data)) { - this._source = { - format: 'base64', - base64: ParseFile.encodeBase64(data), - type: specifiedType - }; - } else if (typeof File !== 'undefined' && data instanceof File) { - this._source = { - format: 'file', - file: data, - type: specifiedType - }; - } else if (data && typeof data.base64 === 'string') { - const base64 = data.base64; - var commaIndex = base64.indexOf(','); - - if (commaIndex !== -1) { - var matches = dataUriRegexp.exec(base64.slice(0, commaIndex + 1)); - // if data URI with type and charset, there will be 4 matches. - this._source = { - format: 'base64', - base64: base64.slice(commaIndex + 1), - type: matches[1] - }; - } else { - this._source = { - format: 'base64', - base64: base64, - type: specifiedType - }; - } - } else { - throw new TypeError('Cannot create a Parse.File with that data.'); - } - } - } - - /** - * Gets the name of the file. Before save is called, this is the filename - * given by the user. After save is called, that name gets prefixed with a - * unique identifier. - * @method name - * @return {String} - */ - name() { - return this._name; - } - - /** - * Gets the url of the file. It is only available after you save the file or - * after you get the file from a Parse.Object. - * @method url - * @param {Object} options An object to specify url options - * @return {String} - */ - url(options) { - options = options || {}; - if (!this._url) { - return; - } - if (options.forceSecure) { - return this._url.replace(/^http:\/\//i, 'https://'); - } else { - return this._url; - } - } - - /** - * Saves the file to the Parse cloud. - * @method save - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} Promise that is resolved when the save finishes. - */ - save(options) { - options = options || {}; - var controller = CoreManager.getFileController(); - if (!this._previousSave) { - if (this._source.format === 'file') { - this._previousSave = controller.saveFile(this._name, this._source).then(res => { - this._name = res.name; - this._url = res.url; - return this; - }); - } else { - this._previousSave = controller.saveBase64(this._name, this._source).then(res => { - this._name = res.name; - this._url = res.url; - return this; - }); - } - } - if (this._previousSave) { - return this._previousSave._thenRunCallbacks(options); - } - } - - toJSON() { - return { - __type: 'File', - name: this._name, - url: this._url - }; - } - - equals(other) { - if (this === other) { - return true; - } - // Unsaved Files are never equal, since they will be saved to different URLs - return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== 'undefined'; - } - - static fromJSON(obj) { - if (obj.__type !== 'File') { - throw new TypeError('JSON object does not represent a ParseFile'); - } - var file = new ParseFile(obj.name); - file._url = obj.url; - return file; - } - - static encodeBase64(bytes) { - var chunks = []; - chunks.length = Math.ceil(bytes.length / 3); - for (var i = 0; i < chunks.length; i++) { - var b1 = bytes[i * 3]; - var b2 = bytes[i * 3 + 1] || 0; - var b3 = bytes[i * 3 + 2] || 0; - - var has2 = i * 3 + 1 < bytes.length; - var has3 = i * 3 + 2 < bytes.length; - - chunks[i] = [b64Digit(b1 >> 2 & 0x3F), b64Digit(b1 << 4 & 0x30 | b2 >> 4 & 0x0F), has2 ? b64Digit(b2 << 2 & 0x3C | b3 >> 6 & 0x03) : '=', has3 ? b64Digit(b3 & 0x3F) : '='].join(''); - } - - return chunks.join(''); - } -} - -var DefaultController = { - saveFile: function (name, source) { - if (source.format !== 'file') { - throw new Error('saveFile can only be used with File-type sources.'); - } - // To directly upload a File, we use a REST-style AJAX request - var headers = { - 'X-Parse-Application-ID': CoreManager.get('APPLICATION_ID'), - 'X-Parse-JavaScript-Key': CoreManager.get('JAVASCRIPT_KEY'), - 'Content-Type': source.type || (source.file ? source.file.type : null) - }; - var url = CoreManager.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += 'files/' + name; - return CoreManager.getRESTController().ajax('POST', url, source.file, headers); - }, - - saveBase64: function (name, source) { - if (source.format !== 'base64') { - throw new Error('saveBase64 can only be used with Base64-type sources.'); - } - var data = { - base64: source.base64 - }; - if (source.type) { - data._ContentType = source.type; - } - - return CoreManager.getRESTController().request('POST', 'files/' + name, data); - } -}; - -CoreManager.setFileController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseGeoPoint.js b/lib/react-native/ParseGeoPoint.js deleted file mode 100644 index e6dcddf43..000000000 --- a/lib/react-native/ParseGeoPoint.js +++ /dev/null @@ -1,186 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParsePromise from './ParsePromise'; - -/** - * Creates a new GeoPoint with any of the following forms:
                              - *
                              - *   new GeoPoint(otherGeoPoint)
                              - *   new GeoPoint(30, 30)
                              - *   new GeoPoint([30, 30])
                              - *   new GeoPoint({latitude: 30, longitude: 30})
                              - *   new GeoPoint()  // defaults to (0, 0)
                              - *   
                              - * @class Parse.GeoPoint - * @constructor - * - *

                              Represents a latitude / longitude point that may be associated - * with a key in a ParseObject or used as a reference point for geo queries. - * This allows proximity-based queries on the key.

                              - * - *

                              Only one key in a class may contain a GeoPoint.

                              - * - *

                              Example:

                              - *   var point = new Parse.GeoPoint(30.0, -20.0);
                              - *   var object = new Parse.Object("PlaceObject");
                              - *   object.set("location", point);
                              - *   object.save();

                              - */ -export default class ParseGeoPoint { - - constructor(arg1, arg2) { - if (Array.isArray(arg1)) { - ParseGeoPoint._validate(arg1[0], arg1[1]); - this._latitude = arg1[0]; - this._longitude = arg1[1]; - } else if (typeof arg1 === 'object') { - ParseGeoPoint._validate(arg1.latitude, arg1.longitude); - this._latitude = arg1.latitude; - this._longitude = arg1.longitude; - } else if (typeof arg1 === 'number' && typeof arg2 === 'number') { - ParseGeoPoint._validate(arg1, arg2); - this._latitude = arg1; - this._longitude = arg2; - } else { - this._latitude = 0; - this._longitude = 0; - } - } - - /** - * North-south portion of the coordinate, in range [-90, 90]. - * Throws an exception if set out of range in a modern browser. - * @property latitude - * @type Number - */ - get latitude() { - return this._latitude; - } - - set latitude(val) { - ParseGeoPoint._validate(val, this.longitude); - this._latitude = val; - } - - /** - * East-west portion of the coordinate, in range [-180, 180]. - * Throws if set out of range in a modern browser. - * @property longitude - * @type Number - */ - get longitude() { - return this._longitude; - } - - set longitude(val) { - ParseGeoPoint._validate(this.latitude, val); - this._longitude = val; - } - - /** - * Returns a JSON representation of the GeoPoint, suitable for Parse. - * @method toJSON - * @return {Object} - */ - toJSON() { - ParseGeoPoint._validate(this._latitude, this._longitude); - return { - __type: 'GeoPoint', - latitude: this._latitude, - longitude: this._longitude - }; - } - - equals(other) { - return other instanceof ParseGeoPoint && this.latitude === other.latitude && this.longitude === other.longitude; - } - - /** - * Returns the distance from this GeoPoint to another in radians. - * @method radiansTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - radiansTo(point) { - var d2r = Math.PI / 180.0; - var lat1rad = this.latitude * d2r; - var long1rad = this.longitude * d2r; - var lat2rad = point.latitude * d2r; - var long2rad = point.longitude * d2r; - - var sinDeltaLatDiv2 = Math.sin((lat1rad - lat2rad) / 2); - var sinDeltaLongDiv2 = Math.sin((long1rad - long2rad) / 2); - // Square of half the straight line chord distance between both points. - var a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2; - a = Math.min(1.0, a); - return 2 * Math.asin(Math.sqrt(a)); - } - - /** - * Returns the distance from this GeoPoint to another in kilometers. - * @method kilometersTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - kilometersTo(point) { - return this.radiansTo(point) * 6371.0; - } - - /** - * Returns the distance from this GeoPoint to another in miles. - * @method milesTo - * @param {Parse.GeoPoint} point the other Parse.GeoPoint. - * @return {Number} - */ - milesTo(point) { - return this.radiansTo(point) * 3958.8; - } - - /** - * Throws an exception if the given lat-long is out of bounds. - */ - static _validate(latitude, longitude) { - if (latitude !== latitude || longitude !== longitude) { - throw new TypeError('GeoPoint latitude and longitude must be valid numbers'); - } - if (latitude < -90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' < -90.0.'); - } - if (latitude > 90.0) { - throw new TypeError('GeoPoint latitude out of bounds: ' + latitude + ' > 90.0.'); - } - if (longitude < -180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' < -180.0.'); - } - if (longitude > 180.0) { - throw new TypeError('GeoPoint longitude out of bounds: ' + longitude + ' > 180.0.'); - } - } - - /** - * Creates a GeoPoint with the user's current location, if available. - * Calls options.success with a new GeoPoint instance or calls options.error. - * @method current - * @param {Object} options An object with success and error callbacks. - * @static - */ - static current(options) { - var promise = new ParsePromise(); - navigator.geolocation.getCurrentPosition(function (location) { - promise.resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude)); - }, function (error) { - promise.reject(error); - }); - - return promise._thenRunCallbacks(options); - } -} \ No newline at end of file diff --git a/lib/react-native/ParseHooks.js b/lib/react-native/ParseHooks.js deleted file mode 100644 index e079fcd51..000000000 --- a/lib/react-native/ParseHooks.js +++ /dev/null @@ -1,125 +0,0 @@ -import CoreManager from './CoreManager'; -import decode from './decode'; -import encode from './encode'; -import ParseError from './ParseError'; -import ParsePromise from './ParsePromise'; - -export function getFunctions() { - return CoreManager.getHooksController().get("functions"); -} - -export function getTriggers() { - return CoreManager.getHooksController().get("triggers"); -} - -export function getFunction(name) { - return CoreManager.getHooksController().get("functions", name); -} - -export function getTrigger(className, triggerName) { - return CoreManager.getHooksController().get("triggers", className, triggerName); -} - -export function createFunction(functionName, url) { - return create({ functionName: functionName, url: url }); -} - -export function createTrigger(className, triggerName, url) { - return create({ className: className, triggerName: triggerName, url: url }); -} - -export function create(hook) { - return CoreManager.getHooksController().create(hook); -} - -export function updateFunction(functionName, url) { - return update({ functionName: functionName, url: url }); -} - -export function updateTrigger(className, triggerName, url) { - return update({ className: className, triggerName: triggerName, url: url }); -} - -export function update(hook) { - return CoreManager.getHooksController().update(hook); -} - -export function removeFunction(functionName) { - return remove({ functionName: functionName }); -} - -export function removeTrigger(className, triggerName) { - return remove({ className: className, triggerName: triggerName }); -} - -export function remove(hook) { - return CoreManager.getHooksController().remove(hook); -} - -var DefaultController = { - - get(type, functionName, triggerName) { - var url = "/hooks/" + type; - if (functionName) { - url += "/" + functionName; - if (triggerName) { - url += "/" + triggerName; - } - } - return this.sendRequest("GET", url); - }, - - create(hook) { - var url; - if (hook.functionName && hook.url) { - url = "/hooks/functions"; - } else if (hook.className && hook.triggerName && hook.url) { - url = "/hooks/triggers"; - } else { - return Promise.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest("POST", url, hook); - }, - - remove(hook) { - var url; - if (hook.functionName) { - url = "/hooks/functions/" + hook.functionName; - delete hook.functionName; - } else if (hook.className && hook.triggerName) { - url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; - delete hook.className; - delete hook.triggerName; - } else { - return Promise.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest("PUT", url, { "__op": "Delete" }); - }, - - update(hook) { - var url; - if (hook.functionName && hook.url) { - url = "/hooks/functions/" + hook.functionName; - delete hook.functionName; - } else if (hook.className && hook.triggerName && hook.url) { - url = "/hooks/triggers/" + hook.className + "/" + hook.triggerName; - delete hook.className; - delete hook.triggerName; - } else { - return Promise.reject({ error: 'invalid hook declaration', code: 143 }); - } - return this.sendRequest('PUT', url, hook); - }, - - sendRequest(method, url, body) { - return CoreManager.getRESTController().request(method, url, body, { useMasterKey: true }).then(res => { - var decoded = decode(res); - if (decoded) { - return ParsePromise.as(decoded); - } - return ParsePromise.error(new ParseError(ParseError.INVALID_JSON, 'The server returned an invalid response.')); - }); - } -}; - -CoreManager.setHooksController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseInstallation.js b/lib/react-native/ParseInstallation.js deleted file mode 100644 index fd29a3f91..000000000 --- a/lib/react-native/ParseInstallation.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseObject from './ParseObject'; - -export default class Installation extends ParseObject { - constructor(attributes) { - super('_Installation'); - if (attributes && typeof attributes === 'object') { - if (!this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - } -} - -ParseObject.registerSubclass('_Installation', Installation); \ No newline at end of file diff --git a/lib/react-native/ParseLiveQuery.js b/lib/react-native/ParseLiveQuery.js deleted file mode 100644 index 3ad072a72..000000000 --- a/lib/react-native/ParseLiveQuery.js +++ /dev/null @@ -1,212 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import EventEmitter from './EventEmitter'; -import LiveQueryClient from './LiveQueryClient'; -import CoreManager from './CoreManager'; -import ParsePromise from './ParsePromise'; - -function open() { - const LiveQueryController = CoreManager.getLiveQueryController(); - LiveQueryController.open(); -} - -function close() { - const LiveQueryController = CoreManager.getLiveQueryController(); - LiveQueryController.close(); -} - -/** - * - * We expose three events to help you monitor the status of the WebSocket connection: - * - *

                              Open - When we establish the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                              - * Parse.LiveQuery.on('open', () => {
                              - * 
                              - * });

                              - * - *

                              Close - When we lose the WebSocket connection to the LiveQuery server, you'll get this event. - * - *

                              - * Parse.LiveQuery.on('close', () => {
                              - * 
                              - * });

                              - * - *

                              Error - When some network error or LiveQuery server error happens, you'll get this event. - * - *

                              - * Parse.LiveQuery.on('error', (error) => {
                              - * 
                              - * });

                              - * - * @class Parse.LiveQuery - * @static - * - */ -let LiveQuery = new EventEmitter(); - -/** - * After open is called, the LiveQuery will try to send a connect request - * to the LiveQuery server. - * - * @method open - */ -LiveQuery.open = open; - -/** - * When you're done using LiveQuery, you can call Parse.LiveQuery.close(). - * This function will close the WebSocket connection to the LiveQuery server, - * cancel the auto reconnect, and unsubscribe all subscriptions based on it. - * If you call query.subscribe() after this, we'll create a new WebSocket - * connection to the LiveQuery server. - * - * @method close - */ - -LiveQuery.close = close; -// Register a default onError callback to make sure we do not crash on error -LiveQuery.on('error', () => {}); - -export default LiveQuery; - -function getSessionToken() { - const controller = CoreManager.getUserController(); - return controller.currentUserAsync().then(currentUser => { - return currentUser ? currentUser.getSessionToken() : undefined; - }); -} - -function getLiveQueryClient() { - return CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); -} - -let defaultLiveQueryClient; -const DefaultLiveQueryController = { - setDefaultLiveQueryClient(liveQueryClient) { - defaultLiveQueryClient = liveQueryClient; - }, - getDefaultLiveQueryClient() { - if (defaultLiveQueryClient) { - return ParsePromise.as(defaultLiveQueryClient); - } - - return getSessionToken().then(sessionToken => { - let liveQueryServerURL = CoreManager.get('LIVEQUERY_SERVER_URL'); - - if (liveQueryServerURL && liveQueryServerURL.indexOf('ws') !== 0) { - throw new Error('You need to set a proper Parse LiveQuery server url before using LiveQueryClient'); - } - - // If we can not find Parse.liveQueryServerURL, we try to extract it from Parse.serverURL - if (!liveQueryServerURL) { - const tempServerURL = CoreManager.get('SERVER_URL'); - let protocol = 'ws://'; - // If Parse is being served over SSL/HTTPS, ensure LiveQuery Server uses 'wss://' prefix - if (tempServerURL.indexOf('https') === 0) { - protocol = 'wss://'; - } - const host = tempServerURL.replace(/^https?:\/\//, ''); - liveQueryServerURL = protocol + host; - CoreManager.set('LIVEQUERY_SERVER_URL', liveQueryServerURL); - } - - const applicationId = CoreManager.get('APPLICATION_ID'); - const javascriptKey = CoreManager.get('JAVASCRIPT_KEY'); - const masterKey = CoreManager.get('MASTER_KEY'); - // Get currentUser sessionToken if possible - defaultLiveQueryClient = new LiveQueryClient({ - applicationId, - serverURL: liveQueryServerURL, - javascriptKey, - masterKey, - sessionToken - }); - // Register a default onError callback to make sure we do not crash on error - // Cannot create these events on a nested way because of EventEmiiter from React Native - defaultLiveQueryClient.on('error', error => { - LiveQuery.emit('error', error); - }); - defaultLiveQueryClient.on('open', () => { - LiveQuery.emit('open'); - }); - defaultLiveQueryClient.on('close', () => { - LiveQuery.emit('close'); - }); - - return defaultLiveQueryClient; - }); - }, - open() { - getLiveQueryClient().then(liveQueryClient => { - this.resolve(liveQueryClient.open()); - }); - }, - close() { - getLiveQueryClient().then(liveQueryClient => { - this.resolve(liveQueryClient.close()); - }); - }, - subscribe(query) { - let subscriptionWrap = new EventEmitter(); - - getLiveQueryClient().then(liveQueryClient => { - if (liveQueryClient.shouldOpen()) { - liveQueryClient.open(); - } - let promiseSessionToken = getSessionToken(); - // new event emitter - return promiseSessionToken.then(sessionToken => { - - let subscription = liveQueryClient.subscribe(query, sessionToken); - // enter, leave create, etc - - subscriptionWrap.id = subscription.id; - subscriptionWrap.query = subscription.query; - subscriptionWrap.sessionToken = subscription.sessionToken; - subscriptionWrap.unsubscribe = subscription.unsubscribe; - // Cannot create these events on a nested way because of EventEmiiter from React Native - subscription.on('open', () => { - subscriptionWrap.emit('open'); - }); - subscription.on('create', object => { - subscriptionWrap.emit('create', object); - }); - subscription.on('update', object => { - subscriptionWrap.emit('update', object); - }); - subscription.on('enter', object => { - subscriptionWrap.emit('enter', object); - }); - subscription.on('leave', object => { - subscriptionWrap.emit('leave', object); - }); - subscription.on('delete', object => { - subscriptionWrap.emit('delete', object); - }); - - this.resolve(); - }); - }); - return subscriptionWrap; - }, - unsubscribe(subscription) { - getLiveQueryClient().then(liveQueryClient => { - this.resolve(liveQueryClient.unsubscribe(subscription)); - }); - }, - _clearCachedDefaultClient() { - defaultLiveQueryClient = null; - } -}; - -CoreManager.setLiveQueryController(DefaultLiveQueryController); \ No newline at end of file diff --git a/lib/react-native/ParseObject.js b/lib/react-native/ParseObject.js deleted file mode 100644 index e92c14e18..000000000 --- a/lib/react-native/ParseObject.js +++ /dev/null @@ -1,1742 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import canBeSerialized from './canBeSerialized'; -import decode from './decode'; -import encode from './encode'; -import equals from './equals'; -import escape from './escape'; -import ParseACL from './ParseACL'; -import parseDate from './parseDate'; -import ParseError from './ParseError'; -import ParseFile from './ParseFile'; -import { opFromJSON, Op, SetOp, UnsetOp, IncrementOp, AddOp, AddUniqueOp, RemoveOp, RelationOp } from './ParseOp'; -import ParsePromise from './ParsePromise'; -import ParseQuery from './ParseQuery'; -import ParseRelation from './ParseRelation'; -import * as SingleInstanceStateController from './SingleInstanceStateController'; -import unique from './unique'; -import * as UniqueInstanceStateController from './UniqueInstanceStateController'; -import unsavedChildren from './unsavedChildren'; - -// Mapping of class names to constructors, so we can populate objects from the -// server with appropriate subclasses of ParseObject -var classMap = {}; - -// Global counter for generating unique local Ids -var localCount = 0; -// Global counter for generating unique Ids for non-single-instance objects -var objectCount = 0; -// On web clients, objects are single-instance: any two objects with the same Id -// will have the same attributes. However, this may be dangerous default -// behavior in a server scenario -var singleInstance = !CoreManager.get('IS_NODE'); -if (singleInstance) { - CoreManager.setObjectStateController(SingleInstanceStateController); -} else { - CoreManager.setObjectStateController(UniqueInstanceStateController); -} - -function getServerUrlPath() { - var serverUrl = CoreManager.get('SERVER_URL'); - if (serverUrl[serverUrl.length - 1] !== '/') { - serverUrl += '/'; - } - var url = serverUrl.replace(/https?:\/\//, ''); - return url.substr(url.indexOf('/')); -} - -/** - * Creates a new model with defined attributes. - * - *

                              You won't normally call this method directly. It is recommended that - * you use a subclass of Parse.Object instead, created by calling - * extend.

                              - * - *

                              However, if you don't want to use a subclass, or aren't sure which - * subclass is appropriate, you can use this form:

                              - *     var object = new Parse.Object("ClassName");
                              - * 
                              - * That is basically equivalent to:
                              - *     var MyClass = Parse.Object.extend("ClassName");
                              - *     var object = new MyClass();
                              - * 

                              - * - * @class Parse.Object - * @constructor - * @param {String} className The class name for the object - * @param {Object} attributes The initial set of data to store in the object. - * @param {Object} options The options for this object instance. - */ -export default class ParseObject { - /** - * The ID of this object, unique within its class. - * @property id - * @type String - */ - constructor(className, attributes, options) { - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - var toSet = null; - this._objCount = objectCount++; - if (typeof className === 'string') { - this.className = className; - if (attributes && typeof attributes === 'object') { - toSet = attributes; - } - } else if (className && typeof className === 'object') { - this.className = className.className; - toSet = {}; - for (var attr in className) { - if (attr !== 'className') { - toSet[attr] = className[attr]; - } - } - if (attributes && typeof attributes === 'object') { - options = attributes; - } - } - if (toSet && !this.set(toSet, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - - /** Prototype getters / setters **/ - - get attributes() { - let stateController = CoreManager.getObjectStateController(); - return Object.freeze(stateController.estimateAttributes(this._getStateIdentifier())); - } - - /** - * The first time this object was saved on the server. - * @property createdAt - * @type Date - */ - get createdAt() { - return this._getServerData().createdAt; - } - - /** - * The last time this object was updated on the server. - * @property updatedAt - * @type Date - */ - get updatedAt() { - return this._getServerData().updatedAt; - } - - /** Private methods **/ - - /** - * Returns a local or server Id used uniquely identify this object - */ - _getId() { - if (typeof this.id === 'string') { - return this.id; - } - if (typeof this._localId === 'string') { - return this._localId; - } - var localId = 'local' + String(localCount++); - this._localId = localId; - return localId; - } - - /** - * Returns a unique identifier used to pull data from the State Controller. - */ - _getStateIdentifier() { - if (singleInstance) { - let id = this.id; - if (!id) { - id = this._getId(); - } - return { - id: id, - className: this.className - }; - } else { - return this; - } - } - - _getServerData() { - let stateController = CoreManager.getObjectStateController(); - return stateController.getServerData(this._getStateIdentifier()); - } - - _clearServerData() { - var serverData = this._getServerData(); - var unset = {}; - for (var attr in serverData) { - unset[attr] = undefined; - } - let stateController = CoreManager.getObjectStateController(); - stateController.setServerData(this._getStateIdentifier(), unset); - } - - _getPendingOps() { - let stateController = CoreManager.getObjectStateController(); - return stateController.getPendingOps(this._getStateIdentifier()); - } - - _clearPendingOps() { - var pending = this._getPendingOps(); - var latest = pending[pending.length - 1]; - var keys = Object.keys(latest); - keys.forEach(key => { - delete latest[key]; - }); - } - - _getDirtyObjectAttributes() { - var attributes = this.attributes; - var stateController = CoreManager.getObjectStateController(); - var objectCache = stateController.getObjectCache(this._getStateIdentifier()); - var dirty = {}; - for (var attr in attributes) { - var val = attributes[attr]; - if (val && typeof val === 'object' && !(val instanceof ParseObject) && !(val instanceof ParseFile) && !(val instanceof ParseRelation)) { - // Due to the way browsers construct maps, the key order will not change - // unless the object is changed - try { - var json = encode(val, false, true); - var stringified = JSON.stringify(json); - if (objectCache[attr] !== stringified) { - dirty[attr] = val; - } - } catch (e) { - // Error occurred, possibly by a nested unsaved pointer in a mutable container - // No matter how it happened, it indicates a change in the attribute - dirty[attr] = val; - } - } - } - return dirty; - } - - _toFullJSON(seen) { - var json = this.toJSON(seen); - json.__type = 'Object'; - json.className = this.className; - return json; - } - - _getSaveJSON() { - var pending = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - var json = {}; - - for (var attr in dirtyObjects) { - json[attr] = new SetOp(dirtyObjects[attr]).toJSON(); - } - for (attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - return json; - } - - _getSaveParams() { - var method = this.id ? 'PUT' : 'POST'; - var body = this._getSaveJSON(); - var path = 'classes/' + this.className; - if (this.id) { - path += '/' + this.id; - } else if (this.className === '_User') { - path = 'users'; - } - return { - method, - body, - path - }; - } - - _finishFetch(serverData) { - if (!this.id && serverData.objectId) { - this.id = serverData.objectId; - } - let stateController = CoreManager.getObjectStateController(); - stateController.initializeState(this._getStateIdentifier()); - var decoded = {}; - for (var attr in serverData) { - if (attr === 'ACL') { - decoded[attr] = new ParseACL(serverData[attr]); - } else if (attr !== 'objectId') { - decoded[attr] = decode(serverData[attr]); - if (decoded[attr] instanceof ParseRelation) { - decoded[attr]._ensureParentAndKey(this, attr); - } - } - } - if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = parseDate(decoded.createdAt); - } - if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = parseDate(decoded.updatedAt); - } - if (!decoded.updatedAt && decoded.createdAt) { - decoded.updatedAt = decoded.createdAt; - } - stateController.commitServerChanges(this._getStateIdentifier(), decoded); - } - - _setExisted(existed) { - let stateController = CoreManager.getObjectStateController(); - let state = stateController.getState(this._getStateIdentifier()); - if (state) { - state.existed = existed; - } - } - - _migrateId(serverId) { - if (this._localId && serverId) { - if (singleInstance) { - let stateController = CoreManager.getObjectStateController(); - let oldState = stateController.removeState(this._getStateIdentifier()); - this.id = serverId; - delete this._localId; - if (oldState) { - stateController.initializeState(this._getStateIdentifier(), oldState); - } - } else { - this.id = serverId; - delete this._localId; - } - } - } - - _handleSaveResponse(response, status) { - var changes = {}; - - var stateController = CoreManager.getObjectStateController(); - var pending = stateController.popPendingState(this._getStateIdentifier()); - for (var attr in pending) { - if (pending[attr] instanceof RelationOp) { - changes[attr] = pending[attr].applyTo(undefined, this, attr); - } else if (!(attr in response)) { - // Only SetOps and UnsetOps should not come back with results - changes[attr] = pending[attr].applyTo(undefined); - } - } - for (attr in response) { - if ((attr === 'createdAt' || attr === 'updatedAt') && typeof response[attr] === 'string') { - changes[attr] = parseDate(response[attr]); - } else if (attr === 'ACL') { - changes[attr] = new ParseACL(response[attr]); - } else if (attr !== 'objectId') { - changes[attr] = decode(response[attr]); - if (changes[attr] instanceof UnsetOp) { - changes[attr] = undefined; - } - } - } - if (changes.createdAt && !changes.updatedAt) { - changes.updatedAt = changes.createdAt; - } - - this._migrateId(response.objectId); - - if (status !== 201) { - this._setExisted(true); - } - - stateController.commitServerChanges(this._getStateIdentifier(), changes); - } - - _handleSaveError() { - this._getPendingOps(); - - let stateController = CoreManager.getObjectStateController(); - stateController.mergeFirstPendingState(this._getStateIdentifier()); - } - - /** Public methods **/ - - initialize() {} - // NOOP - - - /** - * Returns a JSON version of the object suitable for saving to Parse. - * @method toJSON - * @return {Object} - */ - toJSON(seen) { - var seenEntry = this.id ? this.className + ':' + this.id : this; - var seen = seen || [seenEntry]; - var json = {}; - var attrs = this.attributes; - for (var attr in attrs) { - if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { - json[attr] = attrs[attr].toJSON(); - } else { - json[attr] = encode(attrs[attr], false, false, seen); - } - } - var pending = this._getPendingOps(); - for (var attr in pending[0]) { - json[attr] = pending[0][attr].toJSON(); - } - - if (this.id) { - json.objectId = this.id; - } - return json; - } - - /** - * Determines whether this ParseObject is equal to another ParseObject - * @method equals - * @return {Boolean} - */ - equals(other) { - if (this === other) { - return true; - } - return other instanceof ParseObject && this.className === other.className && this.id === other.id && typeof this.id !== 'undefined'; - } - - /** - * Returns true if this object has been modified since its last - * save/refresh. If an attribute is specified, it returns true only if that - * particular attribute has been modified since the last save/refresh. - * @method dirty - * @param {String} attr An attribute name (optional). - * @return {Boolean} - */ - dirty(attr) { - if (!this.id) { - return true; - } - var pendingOps = this._getPendingOps(); - var dirtyObjects = this._getDirtyObjectAttributes(); - if (attr) { - if (dirtyObjects.hasOwnProperty(attr)) { - return true; - } - for (var i = 0; i < pendingOps.length; i++) { - if (pendingOps[i].hasOwnProperty(attr)) { - return true; - } - } - return false; - } - if (Object.keys(pendingOps[0]).length !== 0) { - return true; - } - if (Object.keys(dirtyObjects).length !== 0) { - return true; - } - return false; - } - - /** - * Returns an array of keys that have been modified since last save/refresh - * @method dirtyKeys - * @return {Array of string} - */ - dirtyKeys() { - var pendingOps = this._getPendingOps(); - var keys = {}; - for (var i = 0; i < pendingOps.length; i++) { - for (var attr in pendingOps[i]) { - keys[attr] = true; - } - } - var dirtyObjects = this._getDirtyObjectAttributes(); - for (var attr in dirtyObjects) { - keys[attr] = true; - } - return Object.keys(keys); - } - - /** - * Gets a Pointer referencing this Object. - * @method toPointer - * @return {Object} - */ - toPointer() { - if (!this.id) { - throw new Error('Cannot create a pointer to an unsaved ParseObject'); - } - return { - __type: 'Pointer', - className: this.className, - objectId: this.id - }; - } - - /** - * Gets the value of an attribute. - * @method get - * @param {String} attr The string name of an attribute. - */ - get(attr) { - return this.attributes[attr]; - } - - /** - * Gets a relation on the given class for the attribute. - * @method relation - * @param String attr The attribute to get the relation for. - */ - relation(attr) { - var value = this.get(attr); - if (value) { - if (!(value instanceof ParseRelation)) { - throw new Error('Called relation() on non-relation field ' + attr); - } - value._ensureParentAndKey(this, attr); - return value; - } - return new ParseRelation(this, attr); - } - - /** - * Gets the HTML-escaped value of an attribute. - * @method escape - * @param {String} attr The string name of an attribute. - */ - escape(attr) { - var val = this.attributes[attr]; - if (val == null) { - return ''; - } - - if (typeof val !== 'string') { - if (typeof val.toString !== 'function') { - return ''; - } - val = val.toString(); - } - return escape(val); - } - - /** - * Returns true if the attribute contains a value that is not - * null or undefined. - * @method has - * @param {String} attr The string name of the attribute. - * @return {Boolean} - */ - has(attr) { - var attributes = this.attributes; - if (attributes.hasOwnProperty(attr)) { - return attributes[attr] != null; - } - return false; - } - - /** - * Sets a hash of model attributes on the object. - * - *

                              You can call it with an object containing keys and values, or with one - * key and value. For example:

                              -   *   gameTurn.set({
                              -   *     player: player1,
                              -   *     diceRoll: 2
                              -   *   }, {
                              -   *     error: function(gameTurnAgain, error) {
                              -   *       // The set failed validation.
                              -   *     }
                              -   *   });
                              -   *
                              -   *   game.set("currentPlayer", player2, {
                              -   *     error: function(gameTurnAgain, error) {
                              -   *       // The set failed validation.
                              -   *     }
                              -   *   });
                              -   *
                              -   *   game.set("finished", true);

                              - * - * @method set - * @param {String} key The key to set. - * @param {} value The value to give it. - * @param {Object} options A set of options for the set. - * The only supported option is error. - * @return {Boolean} true if the set succeeded. - */ - set(key, value, options) { - var changes = {}; - var newOps = {}; - if (key && typeof key === 'object') { - changes = key; - options = value; - } else if (typeof key === 'string') { - changes[key] = value; - } else { - return this; - } - - options = options || {}; - var readonly = []; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var k in changes) { - if (k === 'createdAt' || k === 'updatedAt') { - // This property is read-only, but for legacy reasons we silently - // ignore it - continue; - } - if (readonly.indexOf(k) > -1) { - throw new Error('Cannot modify readonly attribute: ' + k); - } - if (options.unset) { - newOps[k] = new UnsetOp(); - } else if (changes[k] instanceof Op) { - newOps[k] = changes[k]; - } else if (changes[k] && typeof changes[k] === 'object' && typeof changes[k].__op === 'string') { - newOps[k] = opFromJSON(changes[k]); - } else if (k === 'objectId' || k === 'id') { - if (typeof changes[k] === 'string') { - this.id = changes[k]; - } - } else if (k === 'ACL' && typeof changes[k] === 'object' && !(changes[k] instanceof ParseACL)) { - newOps[k] = new SetOp(new ParseACL(changes[k])); - } else { - newOps[k] = new SetOp(changes[k]); - } - } - - // Calculate new values - var currentAttributes = this.attributes; - var newValues = {}; - for (var attr in newOps) { - if (newOps[attr] instanceof RelationOp) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr], this, attr); - } else if (!(newOps[attr] instanceof UnsetOp)) { - newValues[attr] = newOps[attr].applyTo(currentAttributes[attr]); - } - } - - // Validate changes - if (!options.ignoreValidation) { - var validation = this.validate(newValues); - if (validation) { - if (typeof options.error === 'function') { - options.error(this, validation); - } - return false; - } - } - - // Consolidate Ops - var pendingOps = this._getPendingOps(); - var last = pendingOps.length - 1; - var stateController = CoreManager.getObjectStateController(); - for (var attr in newOps) { - var nextOp = newOps[attr].mergeWith(pendingOps[last][attr]); - stateController.setPendingOp(this._getStateIdentifier(), attr, nextOp); - } - - return this; - } - - /** - * Remove an attribute from the model. This is a noop if the attribute doesn't - * exist. - * @method unset - * @param {String} attr The string name of an attribute. - */ - unset(attr, options) { - options = options || {}; - options.unset = true; - return this.set(attr, null, options); - } - - /** - * Atomically increments the value of the given attribute the next time the - * object is saved. If no amount is specified, 1 is used by default. - * - * @method increment - * @param attr {String} The key. - * @param amount {Number} The amount to increment by (optional). - */ - increment(attr, amount) { - if (typeof amount === 'undefined') { - amount = 1; - } - if (typeof amount !== 'number') { - throw new Error('Cannot increment by a non-numeric amount.'); - } - return this.set(attr, new IncrementOp(amount)); - } - - /** - * Atomically add an object to the end of the array associated with a given - * key. - * @method add - * @param attr {String} The key. - * @param item {} The item to add. - */ - add(attr, item) { - return this.set(attr, new AddOp([item])); - } - - /** - * Atomically add an object to the array associated with a given key, only - * if it is not already present in the array. The position of the insert is - * not guaranteed. - * - * @method addUnique - * @param attr {String} The key. - * @param item {} The object to add. - */ - addUnique(attr, item) { - return this.set(attr, new AddUniqueOp([item])); - } - - /** - * Atomically remove all instances of an object from the array associated - * with a given key. - * - * @method remove - * @param attr {String} The key. - * @param item {} The object to remove. - */ - remove(attr, item) { - return this.set(attr, new RemoveOp([item])); - } - - /** - * Returns an instance of a subclass of Parse.Op describing what kind of - * modification has been performed on this field since the last time it was - * saved. For example, after calling object.increment("x"), calling - * object.op("x") would return an instance of Parse.Op.Increment. - * - * @method op - * @param attr {String} The key. - * @returns {Parse.Op} The operation, or undefined if none. - */ - op(attr) { - var pending = this._getPendingOps(); - for (var i = pending.length; i--;) { - if (pending[i][attr]) { - return pending[i][attr]; - } - } - } - - /** - * Creates a new model with identical attributes to this one, similar to Backbone.Model's clone() - * @method clone - * @return {Parse.Object} - */ - clone() { - let clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - let attributes = this.attributes; - if (typeof this.constructor.readOnlyAttributes === 'function') { - let readonly = this.constructor.readOnlyAttributes() || []; - // Attributes are frozen, so we have to rebuild an object, - // rather than delete readonly keys - let copy = {}; - for (let a in attributes) { - if (readonly.indexOf(a) < 0) { - copy[a] = attributes[a]; - } - } - attributes = copy; - } - if (clone.set) { - clone.set(attributes); - } - return clone; - } - - /** - * Creates a new instance of this object. Not to be confused with clone() - * @method newInstance - * @return {Parse.Object} - */ - newInstance() { - let clone = new this.constructor(); - if (!clone.className) { - clone.className = this.className; - } - clone.id = this.id; - if (singleInstance) { - // Just return an object with the right id - return clone; - } - - let stateController = CoreManager.getObjectStateController(); - if (stateController) { - stateController.duplicateState(this._getStateIdentifier(), clone._getStateIdentifier()); - } - return clone; - } - - /** - * Returns true if this object has never been saved to Parse. - * @method isNew - * @return {Boolean} - */ - isNew() { - return !this.id; - } - - /** - * Returns true if this object was created by the Parse server when the - * object might have already been there (e.g. in the case of a Facebook - * login) - * @method existed - * @return {Boolean} - */ - existed() { - if (!this.id) { - return false; - } - let stateController = CoreManager.getObjectStateController(); - let state = stateController.getState(this._getStateIdentifier()); - if (state) { - return state.existed; - } - return false; - } - - /** - * Checks if the model is currently in a valid state. - * @method isValid - * @return {Boolean} - */ - isValid() { - return !this.validate(this.attributes); - } - - /** - * You should not call this function directly unless you subclass - * Parse.Object, in which case you can override this method - * to provide additional validation on set and - * save. Your implementation should return - * - * @method validate - * @param {Object} attrs The current data to validate. - * @return {} False if the data is valid. An error object otherwise. - * @see Parse.Object#set - */ - validate(attrs) { - if (attrs.hasOwnProperty('ACL') && !(attrs.ACL instanceof ParseACL)) { - return new ParseError(ParseError.OTHER_CAUSE, 'ACL must be a Parse ACL.'); - } - for (var key in attrs) { - if (!/^[A-Za-z][0-9A-Za-z_]*$/.test(key)) { - return new ParseError(ParseError.INVALID_KEY_NAME); - } - } - return false; - } - - /** - * Returns the ACL for this object. - * @method getACL - * @returns {Parse.ACL} An instance of Parse.ACL. - * @see Parse.Object#get - */ - getACL() { - var acl = this.get('ACL'); - if (acl instanceof ParseACL) { - return acl; - } - return null; - } - - /** - * Sets the ACL to be used for this object. - * @method setACL - * @param {Parse.ACL} acl An instance of Parse.ACL. - * @param {Object} options Optional Backbone-like options object to be - * passed in to set. - * @return {Boolean} Whether the set passed validation. - * @see Parse.Object#set - */ - setACL(acl, options) { - return this.set('ACL', acl, options); - } - - /** - * Clears any changes to this object made since the last call to save() - * @method revert - */ - revert() { - this._clearPendingOps(); - } - - /** - * Clears all attributes on a model - * @method clear - */ - clear() { - var attributes = this.attributes; - var erasable = {}; - var readonly = ['createdAt', 'updatedAt']; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); - } - for (var attr in attributes) { - if (readonly.indexOf(attr) < 0) { - erasable[attr] = true; - } - } - return this.set(erasable, { unset: true }); - } - - /** - * Fetch the model from the server. If the server's representation of the - * model differs from its current attributes, they will be overriden. - * - * @method fetch - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                                - *
                              • success: A Backbone-style success callback. - *
                              • error: An Backbone-style error callback. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * @return {Parse.Promise} A promise that is fulfilled when the fetch - * completes. - */ - fetch(options) { - options = options || {}; - var fetchOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - fetchOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - fetchOptions.sessionToken = options.sessionToken; - } - var controller = CoreManager.getObjectController(); - return controller.fetch(this, true, fetchOptions)._thenRunCallbacks(options); - } - - /** - * Set a hash of model attributes, and save the model to the server. - * updatedAt will be updated when the request returns. - * You can either call it as:
                              -   *   object.save();
                              - * or
                              -   *   object.save(null, options);
                              - * or
                              -   *   object.save(attrs, options);
                              - * or
                              -   *   object.save(key, value, options);
                              - * - * For example,
                              -   *   gameTurn.save({
                              -   *     player: "Jake Cutter",
                              -   *     diceRoll: 2
                              -   *   }, {
                              -   *     success: function(gameTurnAgain) {
                              -   *       // The save was successful.
                              -   *     },
                              -   *     error: function(gameTurnAgain, error) {
                              -   *       // The save failed.  Error is an instance of Parse.Error.
                              -   *     }
                              -   *   });
                              - * or with promises:
                              -   *   gameTurn.save({
                              -   *     player: "Jake Cutter",
                              -   *     diceRoll: 2
                              -   *   }).then(function(gameTurnAgain) {
                              -   *     // The save was successful.
                              -   *   }, function(error) {
                              -   *     // The save failed.  Error is an instance of Parse.Error.
                              -   *   });
                              - * - * @method save - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                                - *
                              • success: A Backbone-style success callback. - *
                              • error: An Backbone-style error callback. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * @return {Parse.Promise} A promise that is fulfilled when the save - * completes. - */ - save(arg1, arg2, arg3) { - var attrs; - var options; - if (typeof arg1 === 'object' || typeof arg1 === 'undefined') { - attrs = arg1; - if (typeof arg2 === 'object') { - options = arg2; - } - } else { - attrs = {}; - attrs[arg1] = arg2; - options = arg3; - } - - // Support save({ success: function() {}, error: function() {} }) - if (!options && attrs) { - options = {}; - if (typeof attrs.success === 'function') { - options.success = attrs.success; - delete attrs.success; - } - if (typeof attrs.error === 'function') { - options.error = attrs.error; - delete attrs.error; - } - } - - if (attrs) { - var validation = this.validate(attrs); - if (validation) { - if (options && typeof options.error === 'function') { - options.error(this, validation); - } - return ParsePromise.error(validation); - } - this.set(attrs, options); - } - - options = options || {}; - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = !!options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken') && typeof options.sessionToken === 'string') { - saveOptions.sessionToken = options.sessionToken; - } - - var controller = CoreManager.getObjectController(); - var unsaved = unsavedChildren(this); - return controller.save(unsaved, saveOptions).then(() => { - return controller.save(this, saveOptions); - })._thenRunCallbacks(options, this); - } - - /** - * Destroy this model on the server if it was already persisted. - * If `wait: true` is passed, waits for the server to respond - * before removal. - * - * @method destroy - * @param {Object} options A Backbone-style callback object. - * Valid options are:
                                - *
                              • success: A Backbone-style success callback - *
                              • error: An Backbone-style error callback. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * @return {Parse.Promise} A promise that is fulfilled when the destroy - * completes. - */ - destroy(options) { - options = options || {}; - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - if (!this.id) { - return ParsePromise.as()._thenRunCallbacks(options); - } - return CoreManager.getObjectController().destroy(this, destroyOptions)._thenRunCallbacks(options); - } - - /** Static methods **/ - - static _clearAllState() { - let stateController = CoreManager.getObjectStateController(); - stateController.clearAllState(); - } - - /** - * Fetches the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                              -   *   Parse.Object.fetchAll([object1, object2, ...], {
                              -   *     success: function(list) {
                              -   *       // All the objects were fetched.
                              -   *     },
                              -   *     error: function(error) {
                              -   *       // An error occurred while fetching one of the objects.
                              -   *     },
                              -   *   });
                              -   * 
                              - * - * @method fetchAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                                - *
                              • success: A Backbone-style success callback. - *
                              • error: An Backbone-style error callback. - *
                              - */ - static fetchAll(list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return CoreManager.getObjectController().fetch(list, true, queryOptions)._thenRunCallbacks(options); - } - - /** - * Fetches the given list of Parse.Object if needed. - * If any error is encountered, stops and calls the error handler. - * - *
                              -   *   Parse.Object.fetchAllIfNeeded([object1, ...], {
                              -   *     success: function(list) {
                              -   *       // Objects were fetched and updated.
                              -   *     },
                              -   *     error: function(error) {
                              -   *       // An error occurred while fetching one of the objects.
                              -   *     },
                              -   *   });
                              -   * 
                              - * - * @method fetchAllIfNeeded - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                                - *
                              • success: A Backbone-style success callback. - *
                              • error: An Backbone-style error callback. - *
                              - */ - static fetchAllIfNeeded(list, options) { - var options = options || {}; - - var queryOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - queryOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - queryOptions.sessionToken = options.sessionToken; - } - return CoreManager.getObjectController().fetch(list, false, queryOptions)._thenRunCallbacks(options); - } - - /** - * Destroy the given list of models on the server if it was already persisted. - * - *

                              Unlike saveAll, if an error occurs while deleting an individual model, - * this method will continue trying to delete the rest of the models if - * possible, except in the case of a fatal error like a connection error. - * - *

                              In particular, the Parse.Error object returned in the case of error may - * be one of two types: - * - *

                                - *
                              • A Parse.Error.AGGREGATE_ERROR. This object's "errors" property is an - * array of other Parse.Error objects. Each error object in this array - * has an "object" property that references the object that could not be - * deleted (for instance, because that object could not be found).
                              • - *
                              • A non-aggregate Parse.Error. This indicates a serious error that - * caused the delete operation to be aborted partway through (for - * instance, a connection failure in the middle of the delete).
                              • - *
                              - * - *
                              -   *   Parse.Object.destroyAll([object1, object2, ...], {
                              -   *     success: function() {
                              -   *       // All the objects were deleted.
                              -   *     },
                              -   *     error: function(error) {
                              -   *       // An error occurred while deleting one or more of the objects.
                              -   *       // If this is an aggregate error, then we can inspect each error
                              -   *       // object individually to determine the reason why a particular
                              -   *       // object was not deleted.
                              -   *       if (error.code === Parse.Error.AGGREGATE_ERROR) {
                              -   *         for (var i = 0; i < error.errors.length; i++) {
                              -   *           console.log("Couldn't delete " + error.errors[i].object.id +
                              -   *             "due to " + error.errors[i].message);
                              -   *         }
                              -   *       } else {
                              -   *         console.log("Delete aborted because of " + error.message);
                              -   *       }
                              -   *     },
                              -   *   });
                              -   * 
                              - * - * @method destroyAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                                - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * @return {Parse.Promise} A promise that is fulfilled when the destroyAll - * completes. - */ - static destroyAll(list, options) { - var options = options || {}; - - var destroyOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - destroyOptions.sessionToken = options.sessionToken; - } - return CoreManager.getObjectController().destroy(list, destroyOptions)._thenRunCallbacks(options); - } - - /** - * Saves the given list of Parse.Object. - * If any error is encountered, stops and calls the error handler. - * - *
                              -   *   Parse.Object.saveAll([object1, object2, ...], {
                              -   *     success: function(list) {
                              -   *       // All the objects were saved.
                              -   *     },
                              -   *     error: function(error) {
                              -   *       // An error occurred while saving one of the objects.
                              -   *     },
                              -   *   });
                              -   * 
                              - * - * @method saveAll - * @param {Array} list A list of Parse.Object. - * @param {Object} options A Backbone-style callback object. - * @static - * Valid options are:
                                - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - */ - static saveAll(list, options) { - var options = options || {}; - - var saveOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - saveOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - saveOptions.sessionToken = options.sessionToken; - } - return CoreManager.getObjectController().save(list, saveOptions)._thenRunCallbacks(options); - } - - /** - * Creates a reference to a subclass of Parse.Object with the given id. This - * does not exist on Parse.Object, only on subclasses. - * - *

                              A shortcut for:

                              -   *  var Foo = Parse.Object.extend("Foo");
                              -   *  var pointerToFoo = new Foo();
                              -   *  pointerToFoo.id = "myObjectId";
                              -   * 
                              - * - * @method createWithoutData - * @param {String} id The ID of the object to create a reference to. - * @static - * @return {Parse.Object} A Parse.Object reference. - */ - static createWithoutData(id) { - var obj = new this(); - obj.id = id; - return obj; - } - - /** - * Creates a new instance of a Parse Object from a JSON representation. - * @method fromJSON - * @param {Object} json The JSON map of the Object's data - * @param {boolean} override In single instance mode, all old server data - * is overwritten if this is set to true - * @static - * @return {Parse.Object} A Parse.Object reference - */ - static fromJSON(json, override) { - if (!json.className) { - throw new Error('Cannot create an object without a className'); - } - var constructor = classMap[json.className]; - var o = constructor ? new constructor() : new ParseObject(json.className); - var otherAttributes = {}; - for (var attr in json) { - if (attr !== 'className' && attr !== '__type') { - otherAttributes[attr] = json[attr]; - } - } - if (override) { - // id needs to be set before clearServerData can work - if (otherAttributes.objectId) { - o.id = otherAttributes.objectId; - } - let preserved = null; - if (typeof o._preserveFieldsOnFetch === 'function') { - preserved = o._preserveFieldsOnFetch(); - } - o._clearServerData(); - if (preserved) { - o._finishFetch(preserved); - } - } - o._finishFetch(otherAttributes); - if (json.objectId) { - o._setExisted(true); - } - return o; - } - - /** - * Registers a subclass of Parse.Object with a specific class name. - * When objects of that class are retrieved from a query, they will be - * instantiated with this subclass. - * This is only necessary when using ES6 subclassing. - * @method registerSubclass - * @param {String} className The class name of the subclass - * @param {Class} constructor The subclass - */ - static registerSubclass(className, constructor) { - if (typeof className !== 'string') { - throw new TypeError('The first argument must be a valid class name.'); - } - if (typeof constructor === 'undefined') { - throw new TypeError('You must supply a subclass constructor.'); - } - if (typeof constructor !== 'function') { - throw new TypeError('You must register the subclass constructor. ' + 'Did you attempt to register an instance of the subclass?'); - } - classMap[className] = constructor; - if (!constructor.className) { - constructor.className = className; - } - } - - /** - * Creates a new subclass of Parse.Object for the given Parse class name. - * - *

                              Every extension of a Parse class will inherit from the most recent - * previous extension of that class. When a Parse.Object is automatically - * created by parsing JSON, it will use the most recent extension of that - * class.

                              - * - *

                              You should call either:

                              -   *     var MyClass = Parse.Object.extend("MyClass", {
                              -   *         Instance methods,
                              -   *         initialize: function(attrs, options) {
                              -   *             this.someInstanceProperty = [],
                              -   *             Other instance properties
                              -   *         }
                              -   *     }, {
                              -   *         Class properties
                              -   *     });
                              - * or, for Backbone compatibility:
                              -   *     var MyClass = Parse.Object.extend({
                              -   *         className: "MyClass",
                              -   *         Instance methods,
                              -   *         initialize: function(attrs, options) {
                              -   *             this.someInstanceProperty = [],
                              -   *             Other instance properties
                              -   *         }
                              -   *     }, {
                              -   *         Class properties
                              -   *     });

                              - * - * @method extend - * @param {String} className The name of the Parse class backing this model. - * @param {Object} protoProps Instance properties to add to instances of the - * class returned from this method. - * @param {Object} classProps Class properties to add the class returned from - * this method. - * @return {Class} A new subclass of Parse.Object. - */ - static extend(className, protoProps, classProps) { - if (typeof className !== 'string') { - if (className && typeof className.className === 'string') { - return ParseObject.extend(className.className, className, protoProps); - } else { - throw new Error('Parse.Object.extend\'s first argument should be the className.'); - } - } - var adjustedClassName = className; - - if (adjustedClassName === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) { - adjustedClassName = '_User'; - } - - var parentProto = ParseObject.prototype; - if (this.hasOwnProperty('__super__') && this.__super__) { - parentProto = this.prototype; - } else if (classMap[adjustedClassName]) { - parentProto = classMap[adjustedClassName].prototype; - } - var ParseObjectSubclass = function (attributes, options) { - this.className = adjustedClassName; - this._objCount = objectCount++; - // Enable legacy initializers - if (typeof this.initialize === 'function') { - this.initialize.apply(this, arguments); - } - - if (attributes && typeof attributes === 'object') { - if (!this.set(attributes || {}, options)) { - throw new Error('Can\'t create an invalid Parse Object'); - } - } - }; - ParseObjectSubclass.className = adjustedClassName; - ParseObjectSubclass.__super__ = parentProto; - - ParseObjectSubclass.prototype = Object.create(parentProto, { - constructor: { - value: ParseObjectSubclass, - enumerable: false, - writable: true, - configurable: true - } - }); - - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - Object.defineProperty(ParseObjectSubclass.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - Object.defineProperty(ParseObjectSubclass, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - ParseObjectSubclass.extend = function (name, protoProps, classProps) { - if (typeof name === 'string') { - return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); - } - return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); - }; - ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; - - classMap[adjustedClassName] = ParseObjectSubclass; - return ParseObjectSubclass; - } - - /** - * Enable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * This is disabled by default in server environments, since it can lead to - * security issues. - * @method enableSingleInstance - */ - static enableSingleInstance() { - singleInstance = true; - CoreManager.setObjectStateController(SingleInstanceStateController); - } - - /** - * Disable single instance objects, where any local objects with the same Id - * share the same attributes, and stay synchronized with each other. - * When disabled, you can have two instances of the same object in memory - * without them sharing attributes. - * @method disableSingleInstance - */ - static disableSingleInstance() { - singleInstance = false; - CoreManager.setObjectStateController(UniqueInstanceStateController); - } -} - -var DefaultController = { - fetch(target, forceFetch, options) { - if (Array.isArray(target)) { - if (target.length < 1) { - return ParsePromise.as([]); - } - var objs = []; - var ids = []; - var className = null; - var results = []; - var error = null; - target.forEach((el, i) => { - if (error) { - return; - } - if (!className) { - className = el.className; - } - if (className !== el.className) { - error = new ParseError(ParseError.INVALID_CLASS_NAME, 'All objects should be of the same class'); - } - if (!el.id) { - error = new ParseError(ParseError.MISSING_OBJECT_ID, 'All objects must have an ID'); - } - if (forceFetch || Object.keys(el._getServerData()).length === 0) { - ids.push(el.id); - objs.push(el); - } - results.push(el); - }); - if (error) { - return ParsePromise.error(error); - } - var query = new ParseQuery(className); - query.containedIn('objectId', ids); - query._limit = ids.length; - return query.find(options).then(objects => { - var idMap = {}; - objects.forEach(o => { - idMap[o.id] = o; - }); - for (var i = 0; i < objs.length; i++) { - var obj = objs[i]; - if (!obj || !obj.id || !idMap[obj.id]) { - if (forceFetch) { - return ParsePromise.error(new ParseError(ParseError.OBJECT_NOT_FOUND, 'All objects must exist on the server.')); - } - } - } - if (!singleInstance) { - // If single instance objects are disabled, we need to replace the - for (var i = 0; i < results.length; i++) { - var obj = results[i]; - if (obj && obj.id && idMap[obj.id]) { - var id = obj.id; - obj._finishFetch(idMap[id].toJSON()); - results[i] = idMap[id]; - } - } - } - return ParsePromise.as(results); - }); - } else { - var RESTController = CoreManager.getRESTController(); - return RESTController.request('GET', 'classes/' + target.className + '/' + target._getId(), {}, options).then((response, status, xhr) => { - if (target instanceof ParseObject) { - target._clearPendingOps(); - target._clearServerData(); - target._finishFetch(response); - } - return target; - }); - } - }, - - destroy(target, options) { - var RESTController = CoreManager.getRESTController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return ParsePromise.as([]); - } - var batches = [[]]; - target.forEach(obj => { - if (!obj.id) { - return; - } - batches[batches.length - 1].push(obj); - if (batches[batches.length - 1].length >= 20) { - batches.push([]); - } - }); - if (batches[batches.length - 1].length === 0) { - // If the last batch is empty, remove it - batches.pop(); - } - var deleteCompleted = ParsePromise.as(); - var errors = []; - batches.forEach(batch => { - deleteCompleted = deleteCompleted.then(() => { - return RESTController.request('POST', 'batch', { - requests: batch.map(obj => { - return { - method: 'DELETE', - path: getServerUrlPath() + 'classes/' + obj.className + '/' + obj._getId(), - body: {} - }; - }) - }, options).then(results => { - for (var i = 0; i < results.length; i++) { - if (results[i] && results[i].hasOwnProperty('error')) { - var err = new ParseError(results[i].error.code, results[i].error.error); - err.object = batch[i]; - errors.push(err); - } - } - }); - }); - }); - return deleteCompleted.then(() => { - if (errors.length) { - var aggregate = new ParseError(ParseError.AGGREGATE_ERROR); - aggregate.errors = errors; - return ParsePromise.error(aggregate); - } - return ParsePromise.as(target); - }); - } else if (target instanceof ParseObject) { - return RESTController.request('DELETE', 'classes/' + target.className + '/' + target._getId(), {}, options).then(() => { - return ParsePromise.as(target); - }); - } - return ParsePromise.as(target); - }, - - save(target, options) { - var RESTController = CoreManager.getRESTController(); - var stateController = CoreManager.getObjectStateController(); - if (Array.isArray(target)) { - if (target.length < 1) { - return ParsePromise.as([]); - } - - var unsaved = target.concat(); - for (var i = 0; i < target.length; i++) { - if (target[i] instanceof ParseObject) { - unsaved = unsaved.concat(unsavedChildren(target[i], true)); - } - } - unsaved = unique(unsaved); - - var filesSaved = ParsePromise.as(); - var pending = []; - unsaved.forEach(el => { - if (el instanceof ParseFile) { - filesSaved = filesSaved.then(() => { - return el.save(); - }); - } else if (el instanceof ParseObject) { - pending.push(el); - } - }); - - return filesSaved.then(() => { - var objectError = null; - return ParsePromise._continueWhile(() => { - return pending.length > 0; - }, () => { - var batch = []; - var nextPending = []; - pending.forEach(el => { - if (batch.length < 20 && canBeSerialized(el)) { - batch.push(el); - } else { - nextPending.push(el); - } - }); - pending = nextPending; - if (batch.length < 1) { - return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Tried to save a batch with a cycle.')); - } - - // Queue up tasks for each object in the batch. - // When every task is ready, the API request will execute - var batchReturned = new ParsePromise(); - var batchReady = []; - var batchTasks = []; - batch.forEach((obj, index) => { - var ready = new ParsePromise(); - batchReady.push(ready); - - stateController.pushPendingState(obj._getStateIdentifier()); - batchTasks.push(stateController.enqueueTask(obj._getStateIdentifier(), function () { - ready.resolve(); - return batchReturned.then((responses, status) => { - if (responses[index].hasOwnProperty('success')) { - obj._handleSaveResponse(responses[index].success, status); - } else { - if (!objectError && responses[index].hasOwnProperty('error')) { - var serverError = responses[index].error; - objectError = new ParseError(serverError.code, serverError.error); - // Cancel the rest of the save - pending = []; - } - obj._handleSaveError(); - } - }); - })); - }); - - ParsePromise.when(batchReady).then(() => { - // Kick off the batch request - return RESTController.request('POST', 'batch', { - requests: batch.map(obj => { - var params = obj._getSaveParams(); - params.path = getServerUrlPath() + params.path; - return params; - }) - }, options); - }).then((response, status, xhr) => { - batchReturned.resolve(response, status); - }); - - return ParsePromise.when(batchTasks); - }).then(() => { - if (objectError) { - return ParsePromise.error(objectError); - } - return ParsePromise.as(target); - }); - }); - } else if (target instanceof ParseObject) { - // copying target lets Flow guarantee the pointer isn't modified elsewhere - var targetCopy = target; - var task = function () { - var params = targetCopy._getSaveParams(); - return RESTController.request(params.method, params.path, params.body, options).then((response, status) => { - targetCopy._handleSaveResponse(response, status); - }, error => { - targetCopy._handleSaveError(); - return ParsePromise.error(error); - }); - }; - - stateController.pushPendingState(target._getStateIdentifier()); - return stateController.enqueueTask(target._getStateIdentifier(), task).then(() => { - return target; - }, error => { - return ParsePromise.error(error); - }); - } - return ParsePromise.as(); - } -}; - -CoreManager.setObjectController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseOp.js b/lib/react-native/ParseOp.js deleted file mode 100644 index db70be82c..000000000 --- a/lib/react-native/ParseOp.js +++ /dev/null @@ -1,434 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import arrayContainsObject from './arrayContainsObject'; -import decode from './decode'; -import encode from './encode'; -import ParseObject from './ParseObject'; -import ParseRelation from './ParseRelation'; -import unique from './unique'; - -export function opFromJSON(json) { - if (!json || !json.__op) { - return null; - } - switch (json.__op) { - case 'Delete': - return new UnsetOp(); - case 'Increment': - return new IncrementOp(json.amount); - case 'Add': - return new AddOp(decode(json.objects)); - case 'AddUnique': - return new AddUniqueOp(decode(json.objects)); - case 'Remove': - return new RemoveOp(decode(json.objects)); - case 'AddRelation': - var toAdd = decode(json.objects); - if (!Array.isArray(toAdd)) { - return new RelationOp([], []); - } - return new RelationOp(toAdd, []); - case 'RemoveRelation': - var toRemove = decode(json.objects); - if (!Array.isArray(toRemove)) { - return new RelationOp([], []); - } - return new RelationOp([], toRemove); - case 'Batch': - var toAdd = []; - var toRemove = []; - for (var i = 0; i < json.ops.length; i++) { - if (json.ops[i].__op === 'AddRelation') { - toAdd = toAdd.concat(decode(json.ops[i].objects)); - } else if (json.ops[i].__op === 'RemoveRelation') { - toRemove = toRemove.concat(decode(json.ops[i].objects)); - } - } - return new RelationOp(toAdd, toRemove); - } - return null; -} - -export class Op { - // Empty parent class - applyTo(value) {} - mergeWith(previous) {} - toJSON() {} -} - -export class SetOp extends Op { - - constructor(value) { - super(); - this._value = value; - } - - applyTo(value) { - return this._value; - } - - mergeWith(previous) { - return new SetOp(this._value); - } - - toJSON() { - return encode(this._value, false, true); - } -} - -export class UnsetOp extends Op { - applyTo(value) { - return undefined; - } - - mergeWith(previous) { - return new UnsetOp(); - } - - toJSON() { - return { __op: 'Delete' }; - } -} - -export class IncrementOp extends Op { - - constructor(amount) { - super(); - if (typeof amount !== 'number') { - throw new TypeError('Increment Op must be initialized with a numeric amount.'); - } - this._amount = amount; - } - - applyTo(value) { - if (typeof value === 'undefined') { - return this._amount; - } - if (typeof value !== 'number') { - throw new TypeError('Cannot increment a non-numeric value.'); - } - return this._amount + value; - } - - mergeWith(previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._amount); - } - if (previous instanceof IncrementOp) { - return new IncrementOp(this.applyTo(previous._amount)); - } - throw new Error('Cannot merge Increment Op with the previous Op'); - } - - toJSON() { - return { __op: 'Increment', amount: this._amount }; - } -} - -export class AddOp extends Op { - - constructor(value) { - super(); - this._value = Array.isArray(value) ? value : [value]; - } - - applyTo(value) { - if (value == null) { - return this._value; - } - if (Array.isArray(value)) { - return value.concat(this._value); - } - throw new Error('Cannot add elements to a non-array value'); - } - - mergeWith(previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddOp) { - return new AddOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge Add Op with the previous Op'); - } - - toJSON() { - return { __op: 'Add', objects: encode(this._value, false, true) }; - } -} - -export class AddUniqueOp extends Op { - - constructor(value) { - super(); - this._value = unique(Array.isArray(value) ? value : [value]); - } - - applyTo(value) { - if (value == null) { - return this._value || []; - } - if (Array.isArray(value)) { - // copying value lets Flow guarantee the pointer isn't modified elsewhere - var valueCopy = value; - var toAdd = []; - this._value.forEach(v => { - if (v instanceof ParseObject) { - if (!arrayContainsObject(valueCopy, v)) { - toAdd.push(v); - } - } else { - if (valueCopy.indexOf(v) < 0) { - toAdd.push(v); - } - } - }); - return value.concat(toAdd); - } - throw new Error('Cannot add elements to a non-array value'); - } - - mergeWith(previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new SetOp(this._value); - } - if (previous instanceof AddUniqueOp) { - return new AddUniqueOp(this.applyTo(previous._value)); - } - throw new Error('Cannot merge AddUnique Op with the previous Op'); - } - - toJSON() { - return { __op: 'AddUnique', objects: encode(this._value, false, true) }; - } -} - -export class RemoveOp extends Op { - - constructor(value) { - super(); - this._value = unique(Array.isArray(value) ? value : [value]); - } - - applyTo(value) { - if (value == null) { - return []; - } - if (Array.isArray(value)) { - var i = value.indexOf(this._value); - var removed = value.concat([]); - for (var i = 0; i < this._value.length; i++) { - var index = removed.indexOf(this._value[i]); - while (index > -1) { - removed.splice(index, 1); - index = removed.indexOf(this._value[i]); - } - if (this._value[i] instanceof ParseObject && this._value[i].id) { - for (var j = 0; j < removed.length; j++) { - if (removed[j] instanceof ParseObject && this._value[i].id === removed[j].id) { - removed.splice(j, 1); - j--; - } - } - } - } - return removed; - } - throw new Error('Cannot remove elements from a non-array value'); - } - - mergeWith(previous) { - if (!previous) { - return this; - } - if (previous instanceof SetOp) { - return new SetOp(this.applyTo(previous._value)); - } - if (previous instanceof UnsetOp) { - return new UnsetOp(); - } - if (previous instanceof RemoveOp) { - var uniques = previous._value.concat([]); - for (var i = 0; i < this._value.length; i++) { - if (this._value[i] instanceof ParseObject) { - if (!arrayContainsObject(uniques, this._value[i])) { - uniques.push(this._value[i]); - } - } else { - if (uniques.indexOf(this._value[i]) < 0) { - uniques.push(this._value[i]); - } - } - } - return new RemoveOp(uniques); - } - throw new Error('Cannot merge Remove Op with the previous Op'); - } - - toJSON() { - return { __op: 'Remove', objects: encode(this._value, false, true) }; - } -} - -export class RelationOp extends Op { - - constructor(adds, removes) { - super(); - this._targetClassName = null; - - if (Array.isArray(adds)) { - this.relationsToAdd = unique(adds.map(this._extractId, this)); - } - - if (Array.isArray(removes)) { - this.relationsToRemove = unique(removes.map(this._extractId, this)); - } - } - - _extractId(obj) { - if (typeof obj === 'string') { - return obj; - } - if (!obj.id) { - throw new Error('You cannot add or remove an unsaved Parse Object from a relation'); - } - if (!this._targetClassName) { - this._targetClassName = obj.className; - } - if (this._targetClassName !== obj.className) { - throw new Error('Tried to create a Relation with 2 different object types: ' + this._targetClassName + ' and ' + obj.className + '.'); - } - return obj.id; - } - - applyTo(value, object, key) { - if (!value) { - if (!object || !key) { - throw new Error('Cannot apply a RelationOp without either a previous value, or an object and a key'); - } - var parent = new ParseObject(object.className); - if (object.id && object.id.indexOf('local') === 0) { - parent._localId = object.id; - } else if (object.id) { - parent.id = object.id; - } - var relation = new ParseRelation(parent, key); - relation.targetClassName = this._targetClassName; - return relation; - } - if (value instanceof ParseRelation) { - if (this._targetClassName) { - if (value.targetClassName) { - if (this._targetClassName !== value.targetClassName) { - throw new Error('Related object must be a ' + value.targetClassName + ', but a ' + this._targetClassName + ' was passed in.'); - } - } else { - value.targetClassName = this._targetClassName; - } - } - return value; - } else { - throw new Error('Relation cannot be applied to a non-relation field'); - } - } - - mergeWith(previous) { - if (!previous) { - return this; - } else if (previous instanceof UnsetOp) { - throw new Error('You cannot modify a relation after deleting it.'); - } else if (previous instanceof RelationOp) { - if (previous._targetClassName && previous._targetClassName !== this._targetClassName) { - throw new Error('Related object must be of class ' + previous._targetClassName + ', but ' + (this._targetClassName || 'null') + ' was passed in.'); - } - var newAdd = previous.relationsToAdd.concat([]); - this.relationsToRemove.forEach(r => { - var index = newAdd.indexOf(r); - if (index > -1) { - newAdd.splice(index, 1); - } - }); - this.relationsToAdd.forEach(r => { - var index = newAdd.indexOf(r); - if (index < 0) { - newAdd.push(r); - } - }); - - var newRemove = previous.relationsToRemove.concat([]); - this.relationsToAdd.forEach(r => { - var index = newRemove.indexOf(r); - if (index > -1) { - newRemove.splice(index, 1); - } - }); - this.relationsToRemove.forEach(r => { - var index = newRemove.indexOf(r); - if (index < 0) { - newRemove.push(r); - } - }); - - var newRelation = new RelationOp(newAdd, newRemove); - newRelation._targetClassName = this._targetClassName; - return newRelation; - } - throw new Error('Cannot merge Relation Op with the previous Op'); - } - - toJSON() { - var idToPointer = id => { - return { - __type: 'Pointer', - className: this._targetClassName, - objectId: id - }; - }; - - var adds = null; - var removes = null; - var pointers = null; - - if (this.relationsToAdd.length > 0) { - pointers = this.relationsToAdd.map(idToPointer); - adds = { __op: 'AddRelation', objects: pointers }; - } - if (this.relationsToRemove.length > 0) { - pointers = this.relationsToRemove.map(idToPointer); - removes = { __op: 'RemoveRelation', objects: pointers }; - } - - if (adds && removes) { - return { __op: 'Batch', ops: [adds, removes] }; - } - - return adds || removes || {}; - } -} \ No newline at end of file diff --git a/lib/react-native/ParsePromise.js b/lib/react-native/ParsePromise.js deleted file mode 100644 index ef7626b6d..000000000 --- a/lib/react-native/ParsePromise.js +++ /dev/null @@ -1,575 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -var isPromisesAPlusCompliant = true; - -/** - * A Promise is returned by async methods as a hook to provide callbacks to be - * called when the async task is fulfilled. - * - *

                              Typical usage would be like:

                              - *    query.find().then(function(results) {
                              - *      results[0].set("foo", "bar");
                              - *      return results[0].saveAsync();
                              - *    }).then(function(result) {
                              - *      console.log("Updated " + result.id);
                              - *    });
                              - * 

                              - * - * @class Parse.Promise - * @constructor - */ -export default class ParsePromise { - constructor(executor) { - this._resolved = false; - this._rejected = false; - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - - if (typeof executor === 'function') { - executor(this.resolve.bind(this), this.reject.bind(this)); - } - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method resolve - * @param {Object} result the result to pass to the callbacks. - */ - resolve(...results) { - if (this._resolved || this._rejected) { - throw new Error('A promise was resolved even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._resolved = true; - this._result = results; - for (var i = 0; i < this._resolvedCallbacks.length; i++) { - this._resolvedCallbacks[i].apply(this, results); - } - - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Marks this promise as fulfilled, firing any callbacks waiting on it. - * @method reject - * @param {Object} error the error to pass to the callbacks. - */ - reject(error) { - if (this._resolved || this._rejected) { - throw new Error('A promise was rejected even though it had already been ' + (this._resolved ? 'resolved' : 'rejected') + '.'); - } - this._rejected = true; - this._error = error; - for (var i = 0; i < this._rejectedCallbacks.length; i++) { - this._rejectedCallbacks[i](error); - } - this._resolvedCallbacks = []; - this._rejectedCallbacks = []; - } - - /** - * Adds callbacks to be called when this promise is fulfilled. Returns a new - * Promise that will be fulfilled when the callback is complete. It allows - * chaining. If the callback itself returns a Promise, then the one returned - * by "then" will not be fulfilled until that one returned by the callback - * is fulfilled. - * @method then - * @param {Function} resolvedCallback Function that is called when this - * Promise is resolved. Once the callback is complete, then the Promise - * returned by "then" will also be fulfilled. - * @param {Function} rejectedCallback Function that is called when this - * Promise is rejected with an error. Once the callback is complete, then - * the promise returned by "then" with be resolved successfully. If - * rejectedCallback is null, or it returns a rejected Promise, then the - * Promise returned by "then" will be rejected with that error. - * @return {Parse.Promise} A new Promise that will be fulfilled after this - * Promise is fulfilled and either callback has completed. If the callback - * returned a Promise, then this Promise will not be fulfilled until that - * one is. - */ - then(resolvedCallback, rejectedCallback) { - var promise = new ParsePromise(); - - var wrappedResolvedCallback = function (...results) { - if (typeof resolvedCallback === 'function') { - if (isPromisesAPlusCompliant) { - try { - results = [resolvedCallback.apply(this, results)]; - } catch (e) { - results = [ParsePromise.error(e)]; - } - } else { - results = [resolvedCallback.apply(this, results)]; - } - } - if (results.length === 1 && ParsePromise.is(results[0])) { - results[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - promise.resolve.apply(promise, results); - } - }; - - var wrappedRejectedCallback = function (error) { - var result = []; - if (typeof rejectedCallback === 'function') { - if (isPromisesAPlusCompliant) { - try { - result = [rejectedCallback(error)]; - } catch (e) { - result = [ParsePromise.error(e)]; - } - } else { - result = [rejectedCallback(error)]; - } - if (result.length === 1 && ParsePromise.is(result[0])) { - result[0].then(function () { - promise.resolve.apply(promise, arguments); - }, function (error) { - promise.reject(error); - }); - } else { - if (isPromisesAPlusCompliant) { - promise.resolve.apply(promise, result); - } else { - promise.reject(result[0]); - } - } - } else { - promise.reject(error); - } - }; - - var runLater = function (fn) { - fn.call(); - }; - if (isPromisesAPlusCompliant) { - if (typeof process !== 'undefined' && typeof process.nextTick === 'function') { - runLater = function (fn) { - process.nextTick(fn); - }; - } else if (typeof setTimeout === 'function') { - runLater = function (fn) { - setTimeout(fn, 0); - }; - } - } - - if (this._resolved) { - runLater(() => { - wrappedResolvedCallback.apply(this, this._result); - }); - } else if (this._rejected) { - runLater(() => { - wrappedRejectedCallback(this._error); - }); - } else { - this._resolvedCallbacks.push(wrappedResolvedCallback); - this._rejectedCallbacks.push(wrappedRejectedCallback); - } - - return promise; - } - - /** - * Add handlers to be called when the promise - * is either resolved or rejected - * @method always - */ - always(callback) { - return this.then(callback, callback); - } - - /** - * Add handlers to be called when the Promise object is resolved - * @method done - */ - done(callback) { - return this.then(callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * Alias for catch(). - * @method fail - */ - fail(callback) { - return this.then(null, callback); - } - - /** - * Add handlers to be called when the Promise object is rejected - * @method catch - */ - catch(callback) { - return this.then(null, callback); - } - - /** - * Run the given callbacks after this promise is fulfilled. - * @method _thenRunCallbacks - * @param optionsOrCallback {} A Backbone-style options callback, or a - * callback function. If this is an options object and contains a "model" - * attributes, that will be passed to error callbacks as the first argument. - * @param model {} If truthy, this will be passed as the first result of - * error callbacks. This is for Backbone-compatability. - * @return {Parse.Promise} A promise that will be resolved after the - * callbacks are run, with the same result as this. - */ - _thenRunCallbacks(optionsOrCallback, model) { - var options = {}; - if (typeof optionsOrCallback === 'function') { - options.success = function (result) { - optionsOrCallback(result, null); - }; - options.error = function (error) { - optionsOrCallback(null, error); - }; - } else if (typeof optionsOrCallback === 'object') { - if (typeof optionsOrCallback.success === 'function') { - options.success = optionsOrCallback.success; - } - if (typeof optionsOrCallback.error === 'function') { - options.error = optionsOrCallback.error; - } - } - - return this.then(function (...results) { - if (options.success) { - options.success.apply(this, results); - } - return ParsePromise.as.apply(ParsePromise, arguments); - }, function (error) { - if (options.error) { - if (typeof model !== 'undefined') { - options.error(model, error); - } else { - options.error(error); - } - } - // By explicitly returning a rejected Promise, this will work with - // either jQuery or Promises/A+ semantics. - return ParsePromise.error(error); - }); - } - - /** - * Adds a callback function that should be called regardless of whether - * this promise failed or succeeded. The callback will be given either the - * array of results for its first argument, or the error as its second, - * depending on whether this Promise was rejected or resolved. Returns a - * new Promise, like "then" would. - * @method _continueWith - * @param {Function} continuation the callback. - */ - _continueWith(continuation) { - return this.then(function (...args) { - return continuation(args, null); - }, function (error) { - return continuation(null, error); - }); - } - - /** - * Returns true iff the given object fulfils the Promise interface. - * @method is - * @param {Object} promise The object to test - * @static - * @return {Boolean} - */ - static is(promise) { - return promise != null && typeof promise.then === 'function'; - } - - /** - * Returns a new promise that is resolved with a given value. - * @method as - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - static as(...values) { - var promise = new ParsePromise(); - promise.resolve.apply(promise, values); - return promise; - } - - /** - * Returns a new promise that is resolved with a given value. - * If that value is a thenable Promise (has a .then() prototype - * method), the new promise will be chained to the end of the - * value. - * @method resolve - * @param value The value to resolve the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - static resolve(value) { - return new ParsePromise((resolve, reject) => { - if (ParsePromise.is(value)) { - value.then(resolve, reject); - } else { - resolve(value); - } - }); - } - - /** - * Returns a new promise that is rejected with a given error. - * @method error - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - static error(...errors) { - var promise = new ParsePromise(); - promise.reject.apply(promise, errors); - return promise; - } - - /** - * Returns a new promise that is rejected with a given error. - * This is an alias for Parse.Promise.error, for compliance with - * the ES6 implementation. - * @method reject - * @param error The error to reject the promise with - * @static - * @return {Parse.Promise} the new promise. - */ - static reject(...errors) { - return ParsePromise.error.apply(null, errors); - } - - /** - * Returns a new promise that is fulfilled when all of the input promises - * are resolved. If any promise in the list fails, then the returned promise - * will be rejected with an array containing the error from each promise. - * If they all succeed, then the returned promise will succeed, with the - * results being the results of all the input - * promises. For example:
                              -   *   var p1 = Parse.Promise.as(1);
                              -   *   var p2 = Parse.Promise.as(2);
                              -   *   var p3 = Parse.Promise.as(3);
                              -   *
                              -   *   Parse.Promise.when(p1, p2, p3).then(function(r1, r2, r3) {
                              -   *     console.log(r1);  // prints 1
                              -   *     console.log(r2);  // prints 2
                              -   *     console.log(r3);  // prints 3
                              -   *   });
                              - * - * The input promises can also be specified as an array:
                              -   *   var promises = [p1, p2, p3];
                              -   *   Parse.Promise.when(promises).then(function(results) {
                              -   *     console.log(results);  // prints [1,2,3]
                              -   *   });
                              -   * 
                              - * @method when - * @param {Array} promises a list of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - static when(promises) { - var objects; - var arrayArgument = Array.isArray(promises); - if (arrayArgument) { - objects = promises; - } else { - objects = arguments; - } - - var total = objects.length; - var hadError = false; - var results = []; - var returnValue = arrayArgument ? [results] : results; - var errors = []; - results.length = objects.length; - errors.length = objects.length; - - if (total === 0) { - return ParsePromise.as.apply(this, returnValue); - } - - var promise = new ParsePromise(); - - var resolveOne = function () { - total--; - if (total <= 0) { - if (hadError) { - promise.reject(errors); - } else { - promise.resolve.apply(promise, returnValue); - } - } - }; - - var chain = function (object, index) { - if (ParsePromise.is(object)) { - object.then(function (result) { - results[index] = result; - resolveOne(); - }, function (error) { - errors[index] = error; - hadError = true; - resolveOne(); - }); - } else { - results[i] = object; - resolveOne(); - } - }; - for (var i = 0; i < objects.length; i++) { - chain(objects[i], i); - } - - return promise; - } - - /** - * Returns a new promise that is fulfilled when all of the promises in the - * iterable argument are resolved. If any promise in the list fails, then - * the returned promise will be immediately rejected with the reason that - * single promise rejected. If they all succeed, then the returned promise - * will succeed, with the results being the results of all the input - * promises. If the iterable provided is empty, the returned promise will - * be immediately resolved. - * - * For example:
                              -   *   var p1 = Parse.Promise.as(1);
                              -   *   var p2 = Parse.Promise.as(2);
                              -   *   var p3 = Parse.Promise.as(3);
                              -   *
                              -   *   Parse.Promise.all([p1, p2, p3]).then(function([r1, r2, r3]) {
                              -   *     console.log(r1);  // prints 1
                              -   *     console.log(r2);  // prints 2
                              -   *     console.log(r3);  // prints 3
                              -   *   });
                              - * - * @method all - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - static all(promises) { - let total = 0; - let objects = []; - - for (let p of promises) { - objects[total++] = p; - } - - if (total === 0) { - return ParsePromise.as([]); - } - - let hadError = false; - let promise = new ParsePromise(); - let resolved = 0; - let results = []; - objects.forEach((object, i) => { - if (ParsePromise.is(object)) { - object.then(result => { - if (hadError) { - return false; - } - results[i] = result; - resolved++; - if (resolved >= total) { - promise.resolve(results); - } - }, error => { - // Reject immediately - promise.reject(error); - hadError = true; - }); - } else { - results[i] = object; - resolved++; - if (!hadError && resolved >= total) { - promise.resolve(results); - } - } - }); - - return promise; - } - - /** - * Returns a new promise that is immediately fulfilled when any of the - * promises in the iterable argument are resolved or rejected. If the - * first promise to complete is resolved, the returned promise will be - * resolved with the same value. Likewise, if the first promise to - * complete is rejected, the returned promise will be rejected with the - * same reason. - * - * @method race - * @param {Iterable} promises an iterable of promises to wait for. - * @static - * @return {Parse.Promise} the new promise. - */ - static race(promises) { - let completed = false; - let promise = new ParsePromise(); - for (let p of promises) { - if (ParsePromise.is(p)) { - p.then(result => { - if (completed) { - return; - } - completed = true; - promise.resolve(result); - }, error => { - if (completed) { - return; - } - completed = true; - promise.reject(error); - }); - } else if (!completed) { - completed = true; - promise.resolve(p); - } - } - - return promise; - } - - /** - * Runs the given asyncFunction repeatedly, as long as the predicate - * function returns a truthy value. Stops repeating if asyncFunction returns - * a rejected promise. - * @method _continueWhile - * @param {Function} predicate should return false when ready to stop. - * @param {Function} asyncFunction should return a Promise. - * @static - */ - static _continueWhile(predicate, asyncFunction) { - if (predicate()) { - return asyncFunction().then(function () { - return ParsePromise._continueWhile(predicate, asyncFunction); - }); - } - return ParsePromise.as(); - } - - static isPromisesAPlusCompliant() { - return isPromisesAPlusCompliant; - } - - static enableAPlusCompliant() { - isPromisesAPlusCompliant = true; - } - - static disableAPlusCompliant() { - isPromisesAPlusCompliant = false; - } -} \ No newline at end of file diff --git a/lib/react-native/ParseQuery.js b/lib/react-native/ParseQuery.js deleted file mode 100644 index a32275dc1..000000000 --- a/lib/react-native/ParseQuery.js +++ /dev/null @@ -1,1113 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import encode from './encode'; -import ParseError from './ParseError'; -import ParseGeoPoint from './ParseGeoPoint'; -import ParseObject from './ParseObject'; -import ParsePromise from './ParsePromise'; - -/** - * Converts a string into a regex that matches it. - * Surrounding with \Q .. \E does this, we just need to escape any \E's in - * the text separately. - */ -function quote(s) { - return '\\Q' + s.replace('\\E', '\\E\\\\E\\Q') + '\\E'; -} - -/** - * Handles pre-populating the result data of a query with select fields, - * making sure that the data object contains keys for all objects that have - * been requested with a select, so that our cached state updates correctly. - */ -function handleSelectResult(data, select) { - var serverDataMask = {}; - - select.forEach(field => { - let hasSubObjectSelect = field.indexOf(".") !== -1; - if (!hasSubObjectSelect && !data.hasOwnProperty(field)) { - // this field was selected, but is missing from the retrieved data - data[field] = undefined; - } else if (hasSubObjectSelect) { - // this field references a sub-object, - // so we need to walk down the path components - let pathComponents = field.split("."); - var obj = data; - var serverMask = serverDataMask; - - pathComponents.forEach((component, index, arr) => { - // add keys if the expected data is missing - if (!obj[component]) { - obj[component] = index == arr.length - 1 ? undefined : {}; - } - obj = obj[component]; - - //add this path component to the server mask so we can fill it in later if needed - if (index < arr.length - 1) { - if (!serverMask[component]) { - serverMask[component] = {}; - } - } - }); - } - }); - - if (Object.keys(serverDataMask).length > 0) { - // When selecting from sub-objects, we don't want to blow away the missing - // information that we may have retrieved before. We've already added any - // missing selected keys to sub-objects, but we still need to add in the - // data for any previously retrieved sub-objects that were not selected. - - let serverData = CoreManager.getObjectStateController().getServerData({ id: data.objectId, className: data.className }); - - function copyMissingDataWithMask(src, dest, mask, copyThisLevel) { - //copy missing elements at this level - if (copyThisLevel) { - for (var key in src) { - if (src.hasOwnProperty(key) && !dest.hasOwnProperty(key)) { - dest[key] = src[key]; - } - } - } - for (var key in mask) { - //traverse into objects as needed - copyMissingDataWithMask(src[key], dest[key], mask[key], true); - } - } - - copyMissingDataWithMask(serverData, data, serverDataMask, false); - } -} - -/** - * Creates a new parse Parse.Query for the given Parse.Object subclass. - * @class Parse.Query - * @constructor - * @param {} objectClass An instance of a subclass of Parse.Object, or a Parse className string. - * - *

                              Parse.Query defines a query that is used to fetch Parse.Objects. The - * most common use case is finding all objects that match a query through the - * find method. For example, this sample code fetches all objects - * of class MyClass. It calls a different function depending on - * whether the fetch succeeded or not. - * - *

                              - * var query = new Parse.Query(MyClass);
                              - * query.find({
                              - *   success: function(results) {
                              - *     // results is an array of Parse.Object.
                              - *   },
                              - *
                              - *   error: function(error) {
                              - *     // error is an instance of Parse.Error.
                              - *   }
                              - * });

                              - * - *

                              A Parse.Query can also be used to retrieve a single object whose id is - * known, through the get method. For example, this sample code fetches an - * object of class MyClass and id myId. It calls a - * different function depending on whether the fetch succeeded or not. - * - *

                              - * var query = new Parse.Query(MyClass);
                              - * query.get(myId, {
                              - *   success: function(object) {
                              - *     // object is an instance of Parse.Object.
                              - *   },
                              - *
                              - *   error: function(object, error) {
                              - *     // error is an instance of Parse.Error.
                              - *   }
                              - * });

                              - * - *

                              A Parse.Query can also be used to count the number of objects that match - * the query without retrieving all of those objects. For example, this - * sample code counts the number of objects of the class MyClass - *

                              - * var query = new Parse.Query(MyClass);
                              - * query.count({
                              - *   success: function(number) {
                              - *     // There are number instances of MyClass.
                              - *   },
                              - *
                              - *   error: function(error) {
                              - *     // error is an instance of Parse.Error.
                              - *   }
                              - * });

                              - */ -export default class ParseQuery { - - constructor(objectClass) { - if (typeof objectClass === 'string') { - if (objectClass === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) { - this.className = '_User'; - } else { - this.className = objectClass; - } - } else if (objectClass instanceof ParseObject) { - this.className = objectClass.className; - } else if (typeof objectClass === 'function') { - if (typeof objectClass.className === 'string') { - this.className = objectClass.className; - } else { - var obj = new objectClass(); - this.className = obj.className; - } - } else { - throw new TypeError('A ParseQuery must be constructed with a ParseObject or class name.'); - } - - this._where = {}; - this._include = []; - this._limit = -1; // negative limit is not sent in the server request - this._skip = 0; - this._extraOptions = {}; - } - - /** - * Adds constraint that at least one of the passed in queries matches. - * @method _orQuery - * @param {Array} queries - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - _orQuery(queries) { - var queryJSON = queries.map(q => { - return q.toJSON().where; - }); - - this._where.$or = queryJSON; - return this; - } - - /** - * Helper for condition queries - */ - _addCondition(key, condition, value) { - if (!this._where[key] || typeof this._where[key] === 'string') { - this._where[key] = {}; - } - this._where[key][condition] = encode(value, false, true); - return this; - } - - /** - * Converts string for regular expression at the beginning - */ - _regexStartWith(string) { - return '^' + quote(string); - } - - /** - * Returns a JSON representation of this query. - * @method toJSON - * @return {Object} The JSON representation of the query. - */ - toJSON() { - var params = { - where: this._where - }; - - if (this._include.length) { - params.include = this._include.join(','); - } - if (this._select) { - params.keys = this._select.join(','); - } - if (this._limit >= 0) { - params.limit = this._limit; - } - if (this._skip > 0) { - params.skip = this._skip; - } - if (this._order) { - params.order = this._order.join(','); - } - for (var key in this._extraOptions) { - params[key] = this._extraOptions[key]; - } - - return params; - } - - /** - * Constructs a Parse.Object whose id is already known by fetching data from - * the server. Either options.success or options.error is called when the - * find completes. - * - * @method get - * @param {String} objectId The id of the object to be fetched. - * @param {Object} options A Backbone-style options object. - * Valid options are:
                                - *
                              • success: A Backbone-style success callback - *
                              • error: An Backbone-style error callback. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * - * @return {Parse.Promise} A promise that is resolved with the result when - * the query completes. - */ - get(objectId, options) { - this.equalTo('objectId', objectId); - - var firstOptions = {}; - if (options && options.hasOwnProperty('useMasterKey')) { - firstOptions.useMasterKey = options.useMasterKey; - } - if (options && options.hasOwnProperty('sessionToken')) { - firstOptions.sessionToken = options.sessionToken; - } - - return this.first(firstOptions).then(response => { - if (response) { - return response; - } - - var errorObject = new ParseError(ParseError.OBJECT_NOT_FOUND, 'Object not found.'); - return ParsePromise.error(errorObject); - })._thenRunCallbacks(options, null); - } - - /** - * Retrieves a list of ParseObjects that satisfy this query. - * Either options.success or options.error is called when the find - * completes. - * - * @method find - * @param {Object} options A Backbone-style options object. Valid options - * are:
                                - *
                              • success: Function to call when the find completes successfully. - *
                              • error: Function to call when the find fails. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * - * @return {Parse.Promise} A promise that is resolved with the results when - * the query completes. - */ - find(options) { - options = options || {}; - - let findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - let controller = CoreManager.getQueryController(); - - let select = this._select; - - return controller.find(this.className, this.toJSON(), findOptions).then(response => { - return response.results.map(data => { - // In cases of relations, the server may send back a className - // on the top level of the payload - let override = response.className || this.className; - if (!data.className) { - data.className = override; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(data, select); - } - - return ParseObject.fromJSON(data, !select); - }); - })._thenRunCallbacks(options); - } - - /** - * Counts the number of objects that match this query. - * Either options.success or options.error is called when the count - * completes. - * - * @method count - * @param {Object} options A Backbone-style options object. Valid options - * are:
                                - *
                              • success: Function to call when the count completes successfully. - *
                              • error: Function to call when the find fails. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * - * @return {Parse.Promise} A promise that is resolved with the count when - * the query completes. - */ - count(options) { - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = CoreManager.getQueryController(); - - var params = this.toJSON(); - params.limit = 0; - params.count = 1; - - return controller.find(this.className, params, findOptions).then(result => { - return result.count; - })._thenRunCallbacks(options); - } - - /** - * Retrieves at most one Parse.Object that satisfies this query. - * - * Either options.success or options.error is called when it completes. - * success is passed the object if there is one. otherwise, undefined. - * - * @method first - * @param {Object} options A Backbone-style options object. Valid options - * are:
                                - *
                              • success: Function to call when the find completes successfully. - *
                              • error: Function to call when the find fails. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * - * @return {Parse.Promise} A promise that is resolved with the object when - * the query completes. - */ - first(options) { - options = options || {}; - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var controller = CoreManager.getQueryController(); - - var params = this.toJSON(); - params.limit = 1; - - var select = this._select; - - return controller.find(this.className, params, findOptions).then(response => { - var objects = response.results; - if (!objects[0]) { - return undefined; - } - if (!objects[0].className) { - objects[0].className = this.className; - } - - // Make sure the data object contains keys for all objects that - // have been requested with a select, so that our cached state - // updates correctly. - if (select) { - handleSelectResult(objects[0], select); - } - - return ParseObject.fromJSON(objects[0], !select); - })._thenRunCallbacks(options); - } - - /** - * Iterates over each result of a query, calling a callback for each one. If - * the callback returns a promise, the iteration will not continue until - * that promise has been fulfilled. If the callback returns a rejected - * promise, then iteration will stop with that error. The items are - * processed in an unspecified order. The query may not have any sort order, - * and may not use limit or skip. - * @method each - * @param {Function} callback Callback that will be called with each result - * of the query. - * @param {Object} options A Backbone-style options object. Valid options - * are:
                                - *
                              • success: Function to call when the iteration completes successfully. - *
                              • error: Function to call when the iteration fails. - *
                              • useMasterKey: In Cloud Code and Node only, causes the Master Key to - * be used for this request. - *
                              • sessionToken: A valid session token, used for making a request on - * behalf of a specific user. - *
                              - * @return {Parse.Promise} A promise that will be fulfilled once the - * iteration has completed. - */ - each(callback, options) { - options = options || {}; - - if (this._order || this._skip || this._limit >= 0) { - return ParsePromise.error('Cannot iterate on a query with sort, skip, or limit.')._thenRunCallbacks(options); - } - - new ParsePromise(); - - - var query = new ParseQuery(this.className); - // We can override the batch size from the options. - // This is undocumented, but useful for testing. - query._limit = options.batchSize || 100; - query._include = this._include.map(i => { - return i; - }); - if (this._select) { - query._select = this._select.map(s => { - return s; - }); - } - - query._where = {}; - for (var attr in this._where) { - var val = this._where[attr]; - if (Array.isArray(val)) { - query._where[attr] = val.map(v => { - return v; - }); - } else if (val && typeof val === 'object') { - var conditionMap = {}; - query._where[attr] = conditionMap; - for (var cond in val) { - conditionMap[cond] = val[cond]; - } - } else { - query._where[attr] = val; - } - } - - query.ascending('objectId'); - - var findOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - findOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('sessionToken')) { - findOptions.sessionToken = options.sessionToken; - } - - var finished = false; - return ParsePromise._continueWhile(() => { - return !finished; - }, () => { - return query.find(findOptions).then(results => { - var callbacksDone = ParsePromise.as(); - results.forEach(result => { - callbacksDone = callbacksDone.then(() => { - return callback(result); - }); - }); - - return callbacksDone.then(() => { - if (results.length >= query._limit) { - query.greaterThan('objectId', results[results.length - 1].id); - } else { - finished = true; - } - }); - }); - })._thenRunCallbacks(options); - } - - /** Query Conditions **/ - - /** - * Adds a constraint to the query that requires a particular key's value to - * be equal to the provided value. - * @method equalTo - * @param {String} key The key to check. - * @param value The value that the Parse.Object must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - equalTo(key, value) { - if (typeof value === 'undefined') { - return this.doesNotExist(key); - } - - this._where[key] = encode(value, false, true); - return this; - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be not equal to the provided value. - * @method notEqualTo - * @param {String} key The key to check. - * @param value The value that must not be equalled. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - notEqualTo(key, value) { - return this._addCondition(key, '$ne', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than the provided value. - * @method lessThan - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - lessThan(key, value) { - return this._addCondition(key, '$lt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than the provided value. - * @method greaterThan - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - greaterThan(key, value) { - return this._addCondition(key, '$gt', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be less than or equal to the provided value. - * @method lessThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an upper bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - lessThanOrEqualTo(key, value) { - return this._addCondition(key, '$lte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be greater than or equal to the provided value. - * @method greaterThanOrEqualTo - * @param {String} key The key to check. - * @param value The value that provides an lower bound. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - greaterThanOrEqualTo(key, value) { - return this._addCondition(key, '$gte', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * be contained in the provided list of values. - * @method containedIn - * @param {String} key The key to check. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - containedIn(key, value) { - return this._addCondition(key, '$in', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * not be contained in the provided list of values. - * @method notContainedIn - * @param {String} key The key to check. - * @param {Array} values The values that will not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - notContainedIn(key, value) { - return this._addCondition(key, '$nin', value); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values. - * @method containsAll - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The values that will match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - containsAll(key, values) { - return this._addCondition(key, '$all', values); - } - - /** - * Adds a constraint to the query that requires a particular key's value to - * contain each one of the provided list of values starting with given strings. - * @method containsAllStartingWith - * @param {String} key The key to check. This key's value must be an array. - * @param {Array} values The string values that will match as starting string. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - containsAllStartingWith(key, values) { - var _this = this; - if (!Array.isArray(values)) { - values = [values]; - } - - values = values.map(function (value) { - return { "$regex": _this._regexStartWith(value) }; - }); - - return this.containsAll(key, values); - } - - /** - * Adds a constraint for finding objects that contain the given key. - * @method exists - * @param {String} key The key that should exist. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - exists(key) { - return this._addCondition(key, '$exists', true); - } - - /** - * Adds a constraint for finding objects that do not contain a given key. - * @method doesNotExist - * @param {String} key The key that should not exist - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - doesNotExist(key) { - return this._addCondition(key, '$exists', false); - } - - /** - * Adds a regular expression constraint for finding string values that match - * the provided regular expression. - * This may be slow for large datasets. - * @method matches - * @param {String} key The key that the string to match is stored in. - * @param {RegExp} regex The regular expression pattern to match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - matches(key, regex, modifiers) { - this._addCondition(key, '$regex', regex); - if (!modifiers) { - modifiers = ''; - } - if (regex.ignoreCase) { - modifiers += 'i'; - } - if (regex.multiline) { - modifiers += 'm'; - } - if (modifiers.length) { - this._addCondition(key, '$options', modifiers); - } - return this; - } - - /** - * Adds a constraint that requires that a key's value matches a Parse.Query - * constraint. - * @method matchesQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - matchesQuery(key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$inQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value not matches a - * Parse.Query constraint. - * @method doesNotMatchQuery - * @param {String} key The key that the contains the object to match the - * query. - * @param {Parse.Query} query The query that should not match. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - doesNotMatchQuery(key, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$notInQuery', queryJSON); - } - - /** - * Adds a constraint that requires that a key's value matches a value in - * an object returned by a different Parse.Query. - * @method matchesKeyInQuery - * @param {String} key The key that contains the value that is being - * matched. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - matchesKeyInQuery(key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$select', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint that requires that a key's value not match a value in - * an object returned by a different Parse.Query. - * @method doesNotMatchKeyInQuery - * @param {String} key The key that contains the value that is being - * excluded. - * @param {String} queryKey The key in the objects returned by the query to - * match against. - * @param {Parse.Query} query The query to run. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - doesNotMatchKeyInQuery(key, queryKey, query) { - var queryJSON = query.toJSON(); - queryJSON.className = query.className; - return this._addCondition(key, '$dontSelect', { - key: queryKey, - query: queryJSON - }); - } - - /** - * Adds a constraint for finding string values that contain a provided - * string. This may be slow for large datasets. - * @method contains - * @param {String} key The key that the string to match is stored in. - * @param {String} substring The substring that the value must contain. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - contains(key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value)); - } - - /** - * Adds a constraint for finding string values that start with a provided - * string. This query will use the backend index, so it will be fast even - * for large datasets. - * @method startsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} prefix The substring that the value must start with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - startsWith(key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', this._regexStartWith(value)); - } - - /** - * Adds a constraint for finding string values that end with a provided - * string. This will be slow for large datasets. - * @method endsWith - * @param {String} key The key that the string to match is stored in. - * @param {String} suffix The substring that the value must end with. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - endsWith(key, value) { - if (typeof value !== 'string') { - throw new Error('The value being searched for must be a string.'); - } - return this._addCondition(key, '$regex', quote(value) + '$'); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given. - * @method near - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - near(key, point) { - if (!(point instanceof ParseGeoPoint)) { - // Try to cast it as a GeoPoint - point = new ParseGeoPoint(point); - } - return this._addCondition(key, '$nearSphere', point); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * @method withinRadians - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in radians) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - withinRadians(key, point, distance) { - this.near(key, point); - return this._addCondition(key, '$maxDistance', distance); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 3958.8 miles. - * @method withinMiles - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in miles) of results to - * return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - withinMiles(key, point, distance) { - return this.withinRadians(key, point, distance / 3958.8); - } - - /** - * Adds a proximity based constraint for finding objects with key point - * values near the point given and within the maximum distance given. - * Radius of earth used is 6371.0 kilometers. - * @method withinKilometers - * @param {String} key The key that the Parse.GeoPoint is stored in. - * @param {Parse.GeoPoint} point The reference Parse.GeoPoint that is used. - * @param {Number} maxDistance Maximum distance (in kilometers) of results - * to return. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - withinKilometers(key, point, distance) { - return this.withinRadians(key, point, distance / 6371.0); - } - - /** - * Adds a constraint to the query that requires a particular key's - * coordinates be contained within a given rectangular geographic bounding - * box. - * @method withinGeoBox - * @param {String} key The key to be constrained. - * @param {Parse.GeoPoint} southwest - * The lower-left inclusive corner of the box. - * @param {Parse.GeoPoint} northeast - * The upper-right inclusive corner of the box. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - withinGeoBox(key, southwest, northeast) { - if (!(southwest instanceof ParseGeoPoint)) { - southwest = new ParseGeoPoint(southwest); - } - if (!(northeast instanceof ParseGeoPoint)) { - northeast = new ParseGeoPoint(northeast); - } - this._addCondition(key, '$within', { '$box': [southwest, northeast] }); - return this; - } - - /** Query Orderings **/ - - /** - * Sorts the results in ascending order by the given key. - * - * @method ascending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - ascending(...keys) { - this._order = []; - return this.addAscending.apply(this, keys); - } - - /** - * Sorts the results in ascending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addAscending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - addAscending(...keys) { - if (!this._order) { - this._order = []; - } - keys.forEach(key => { - if (Array.isArray(key)) { - key = key.join(); - } - this._order = this._order.concat(key.replace(/\s/g, '').split(',')); - }); - - return this; - } - - /** - * Sorts the results in descending order by the given key. - * - * @method descending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - descending(...keys) { - this._order = []; - return this.addDescending.apply(this, keys); - } - - /** - * Sorts the results in descending order by the given key, - * but can also add secondary sort descriptors without overwriting _order. - * - * @method addDescending - * @param {(String|String[]|...String} key The key to order by, which is a - * string of comma separated values, or an Array of keys, or multiple keys. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - addDescending(...keys) { - if (!this._order) { - this._order = []; - } - keys.forEach(key => { - if (Array.isArray(key)) { - key = key.join(); - } - this._order = this._order.concat(key.replace(/\s/g, '').split(',').map(k => { - return '-' + k; - })); - }); - - return this; - } - - /** Query Options **/ - - /** - * Sets the number of results to skip before returning any results. - * This is useful for pagination. - * Default is to skip zero results. - * @method skip - * @param {Number} n the number of results to skip. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - skip(n) { - if (typeof n !== 'number' || n < 0) { - throw new Error('You can only skip by a positive number'); - } - this._skip = n; - return this; - } - - /** - * Sets the limit of the number of results to return. The default limit is - * 100, with a maximum of 1000 results being returned at a time. - * @method limit - * @param {Number} n the number of results to limit to. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - limit(n) { - if (typeof n !== 'number') { - throw new Error('You can only set the limit to a numeric value'); - } - this._limit = n; - return this; - } - - /** - * Includes nested Parse.Objects for the provided key. You can use dot - * notation to specify which fields in the included object are also fetched. - * @method include - * @param {String} key The name of the key to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - include(...keys) { - keys.forEach(key => { - if (Array.isArray(key)) { - this._include = this._include.concat(key); - } else { - this._include.push(key); - } - }); - return this; - } - - /** - * Restricts the fields of the returned Parse.Objects to include only the - * provided keys. If this is called multiple times, then all of the keys - * specified in each of the calls will be included. - * @method select - * @param {Array} keys The names of the keys to include. - * @return {Parse.Query} Returns the query, so you can chain this call. - */ - select(...keys) { - if (!this._select) { - this._select = []; - } - keys.forEach(key => { - if (Array.isArray(key)) { - this._select = this._select.concat(key); - } else { - this._select.push(key); - } - }); - return this; - } - - /** - * Subscribe this query to get liveQuery updates - * @method subscribe - * @return {LiveQuerySubscription} Returns the liveQuerySubscription, it's an event emitter - * which can be used to get liveQuery updates. - */ - subscribe() { - let controller = CoreManager.getLiveQueryController(); - return controller.subscribe(this); - } - - /** - * Constructs a Parse.Query that is the OR of the passed in queries. For - * example: - *
                              var compoundQuery = Parse.Query.or(query1, query2, query3);
                              - * - * will create a compoundQuery that is an or of the query1, query2, and - * query3. - * @method or - * @param {...Parse.Query} var_args The list of queries to OR. - * @static - * @return {Parse.Query} The query that is the OR of the passed in queries. - */ - static or(...queries) { - var className = null; - queries.forEach(q => { - if (!className) { - className = q.className; - } - - if (className !== q.className) { - throw new Error('All queries must be for the same class.'); - } - }); - - var query = new ParseQuery(className); - query._orQuery(queries); - return query; - } -} - -var DefaultController = { - find(className, params, options) { - var RESTController = CoreManager.getRESTController(); - - return RESTController.request('GET', 'classes/' + className, params, options); - } -}; - -CoreManager.setQueryController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseRelation.js b/lib/react-native/ParseRelation.js deleted file mode 100644 index c07b48cc1..000000000 --- a/lib/react-native/ParseRelation.js +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import { RelationOp } from './ParseOp'; -import ParseObject from './ParseObject'; -import ParseQuery from './ParseQuery'; - -/** - * Creates a new Relation for the given parent object and key. This - * constructor should rarely be used directly, but rather created by - * Parse.Object.relation. - * @class Parse.Relation - * @constructor - * @param {Parse.Object} parent The parent of this relation. - * @param {String} key The key for this relation on the parent. - * - *

                              - * A class that is used to access all of the children of a many-to-many - * relationship. Each instance of Parse.Relation is associated with a - * particular parent object and key. - *

                              - */ -export default class ParseRelation { - - constructor(parent, key) { - this.parent = parent; - this.key = key; - this.targetClassName = null; - } - - /** - * Makes sure that this relation has the right parent and key. - */ - _ensureParentAndKey(parent, key) { - this.key = this.key || key; - if (this.key !== key) { - throw new Error('Internal Error. Relation retrieved from two different keys.'); - } - if (this.parent) { - if (this.parent.className !== parent.className) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - if (this.parent.id) { - if (this.parent.id !== parent.id) { - throw new Error('Internal Error. Relation retrieved from two different Objects.'); - } - } else if (parent.id) { - this.parent = parent; - } - } else { - this.parent = parent; - } - } - - /** - * Adds a Parse.Object or an array of Parse.Objects to the relation. - * @method add - * @param {} objects The item or items to add. - */ - add(objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new RelationOp(objects, []); - var parent = this.parent; - if (!parent) { - throw new Error('Cannot add to a Relation without a parent'); - } - parent.set(this.key, change); - this.targetClassName = change._targetClassName; - return parent; - } - - /** - * Removes a Parse.Object or an array of Parse.Objects from this relation. - * @method remove - * @param {} objects The item or items to remove. - */ - remove(objects) { - if (!Array.isArray(objects)) { - objects = [objects]; - } - - var change = new RelationOp([], objects); - if (!this.parent) { - throw new Error('Cannot remove from a Relation without a parent'); - } - this.parent.set(this.key, change); - this.targetClassName = change._targetClassName; - } - - /** - * Returns a JSON version of the object suitable for saving to disk. - * @method toJSON - * @return {Object} - */ - toJSON() { - return { - __type: 'Relation', - className: this.targetClassName - }; - } - - /** - * Returns a Parse.Query that is limited to objects in this - * relation. - * @method query - * @return {Parse.Query} - */ - query() { - var query; - var parent = this.parent; - if (!parent) { - throw new Error('Cannot construct a query for a Relation without a parent'); - } - if (!this.targetClassName) { - query = new ParseQuery(parent.className); - query._extraOptions.redirectClassNameForKey = this.key; - } else { - query = new ParseQuery(this.targetClassName); - } - query._addCondition('$relatedTo', 'object', { - __type: 'Pointer', - className: parent.className, - objectId: parent.id - }); - query._addCondition('$relatedTo', 'key', this.key); - - return query; - } -} \ No newline at end of file diff --git a/lib/react-native/ParseRole.js b/lib/react-native/ParseRole.js deleted file mode 100644 index 04164b2e4..000000000 --- a/lib/react-native/ParseRole.js +++ /dev/null @@ -1,133 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseACL from './ParseACL'; -import ParseError from './ParseError'; -import ParseObject from './ParseObject'; - -/** - * Represents a Role on the Parse server. Roles represent groupings of - * Users for the purposes of granting permissions (e.g. specifying an ACL - * for an Object). Roles are specified by their sets of child users and - * child roles, all of which are granted any permissions that the parent - * role has. - * - *

                              Roles must have a name (which cannot be changed after creation of the - * role), and must specify an ACL.

                              - * @class Parse.Role - * @constructor - * @param {String} name The name of the Role to create. - * @param {Parse.ACL} acl The ACL for this role. Roles must have an ACL. - * A Parse.Role is a local representation of a role persisted to the Parse - * cloud. - */ -export default class ParseRole extends ParseObject { - constructor(name, acl) { - super('_Role'); - if (typeof name === 'string' && acl instanceof ParseACL) { - this.setName(name); - this.setACL(acl); - } - } - - /** - * Gets the name of the role. You can alternatively call role.get("name") - * - * @method getName - * @return {String} the name of the role. - */ - getName() { - const name = this.get('name'); - if (name == null || typeof name === 'string') { - return name; - } - return ''; - } - - /** - * Sets the name for a role. This value must be set before the role has - * been saved to the server, and cannot be set once the role has been - * saved. - * - *

                              - * A role's name can only contain alphanumeric characters, _, -, and - * spaces. - *

                              - * - *

                              This is equivalent to calling role.set("name", name)

                              - * - * @method setName - * @param {String} name The name of the role. - * @param {Object} options Standard options object with success and error - * callbacks. - */ - setName(name, options) { - return this.set('name', name, options); - } - - /** - * Gets the Parse.Relation for the Parse.Users that are direct - * children of this role. These users are granted any privileges that this - * role has been granted (e.g. read or write access through ACLs). You can - * add or remove users from the role through this relation. - * - *

                              This is equivalent to calling role.relation("users")

                              - * - * @method getUsers - * @return {Parse.Relation} the relation for the users belonging to this - * role. - */ - getUsers() { - return this.relation('users'); - } - - /** - * Gets the Parse.Relation for the Parse.Roles that are direct - * children of this role. These roles' users are granted any privileges that - * this role has been granted (e.g. read or write access through ACLs). You - * can add or remove child roles from this role through this relation. - * - *

                              This is equivalent to calling role.relation("roles")

                              - * - * @method getRoles - * @return {Parse.Relation} the relation for the roles belonging to this - * role. - */ - getRoles() { - return this.relation('roles'); - } - - validate(attrs, options) { - var isInvalid = super.validate(attrs, options); - if (isInvalid) { - return isInvalid; - } - - if ('name' in attrs && attrs.name !== this.getName()) { - var newName = attrs.name; - if (this.id && this.id !== attrs.objectId) { - // Check to see if the objectId being set matches this.id - // This happens during a fetch -- the id is set before calling fetch - // Let the name be set in this case - return new ParseError(ParseError.OTHER_CAUSE, 'A role\'s name can only be set before it has been saved.'); - } - if (typeof newName !== 'string') { - return new ParseError(ParseError.OTHER_CAUSE, 'A role\'s name must be a String.'); - } - if (!/^[0-9a-zA-Z\-_ ]+$/.test(newName)) { - return new ParseError(ParseError.OTHER_CAUSE, 'A role\'s name can be only contain alphanumeric characters, _, ' + '-, and spaces.'); - } - } - return false; - } -} - -ParseObject.registerSubclass('_Role', ParseRole); \ No newline at end of file diff --git a/lib/react-native/ParseSession.js b/lib/react-native/ParseSession.js deleted file mode 100644 index f1554fc9a..000000000 --- a/lib/react-native/ParseSession.js +++ /dev/null @@ -1,114 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import isRevocableSession from './isRevocableSession'; -import ParseObject from './ParseObject'; -import ParsePromise from './ParsePromise'; -import ParseUser from './ParseUser'; - -/** - * @class Parse.Session - * @constructor - * - *

                              A Parse.Session object is a local representation of a revocable session. - * This class is a subclass of a Parse.Object, and retains the same - * functionality of a Parse.Object.

                              - */ -export default class ParseSession extends ParseObject { - constructor(attributes) { - super('_Session'); - if (attributes && typeof attributes === 'object') { - if (!this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Session'); - } - } - } - - /** - * Returns the session token string. - * @method getSessionToken - * @return {String} - */ - getSessionToken() { - const token = this.get('sessionToken'); - if (typeof token === 'string') { - return token; - } - return ''; - } - - static readOnlyAttributes() { - return ['createdWith', 'expiresAt', 'installationId', 'restricted', 'sessionToken', 'user']; - } - - /** - * Retrieves the Session object for the currently logged in session. - * @method current - * @static - * @return {Parse.Promise} A promise that is resolved with the Parse.Session - * object after it has been fetched. If there is no current user, the - * promise will be rejected. - */ - static current(options) { - options = options || {}; - var controller = CoreManager.getSessionController(); - - var sessionOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - sessionOptions.useMasterKey = options.useMasterKey; - } - return ParseUser.currentAsync().then(user => { - if (!user) { - return ParsePromise.error('There is no current user.'); - } - user.getSessionToken(); - - sessionOptions.sessionToken = user.getSessionToken(); - return controller.getSession(sessionOptions); - }); - } - - /** - * Determines whether the current session token is revocable. - * This method is useful for migrating Express.js or Node.js web apps to - * use revocable sessions. If you are migrating an app that uses the Parse - * SDK in the browser only, please use Parse.User.enableRevocableSession() - * instead, so that sessions can be automatically upgraded. - * @method isCurrentSessionRevocable - * @static - * @return {Boolean} - */ - static isCurrentSessionRevocable() { - var currentUser = ParseUser.current(); - if (currentUser) { - return isRevocableSession(currentUser.getSessionToken() || ''); - } - return false; - } -} - -ParseObject.registerSubclass('_Session', ParseSession); - -var DefaultController = { - getSession(options) { - var RESTController = CoreManager.getRESTController(); - var session = new ParseSession(); - - return RESTController.request('GET', 'sessions/me', {}, options).then(sessionData => { - session._finishFetch(sessionData); - session._setExisted(true); - return session; - }); - } -}; - -CoreManager.setSessionController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/ParseUser.js b/lib/react-native/ParseUser.js deleted file mode 100644 index 129c4cfbb..000000000 --- a/lib/react-native/ParseUser.js +++ /dev/null @@ -1,952 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import isRevocableSession from './isRevocableSession'; -import ParseError from './ParseError'; -import ParseObject from './ParseObject'; -import ParsePromise from './ParsePromise'; -import ParseSession from './ParseSession'; -import Storage from './Storage'; - -var CURRENT_USER_KEY = 'currentUser'; -var canUseCurrentUser = !CoreManager.get('IS_NODE'); -var currentUserCacheMatchesDisk = false; -var currentUserCache = null; - -var authProviders = {}; - -/** - * @class Parse.User - * @constructor - * - *

                              A Parse.User object is a local representation of a user persisted to the - * Parse cloud. This class is a subclass of a Parse.Object, and retains the - * same functionality of a Parse.Object, but also extends it with various - * user specific methods, like authentication, signing up, and validation of - * uniqueness.

                              - */ -export default class ParseUser extends ParseObject { - constructor(attributes) { - super('_User'); - if (attributes && typeof attributes === 'object') { - if (!this.set(attributes || {})) { - throw new Error('Can\'t create an invalid Parse User'); - } - } - } - - /** - * Request a revocable session token to replace the older style of token. - * @method _upgradeToRevocableSession - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is resolved when the replacement - * token has been fetched. - */ - _upgradeToRevocableSession(options) { - options = options || {}; - - var upgradeOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - upgradeOptions.useMasterKey = options.useMasterKey; - } - - var controller = CoreManager.getUserController(); - return controller.upgradeToRevocableSession(this, upgradeOptions)._thenRunCallbacks(options); - } - - /** - * Unlike in the Android/iOS SDKs, logInWith is unnecessary, since you can - * call linkWith on the user (even if it doesn't exist yet on the server). - * @method _linkWith - */ - _linkWith(provider, options) { - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[provider]; - } else { - authType = provider.getAuthType(); - } - if (options && options.hasOwnProperty('authData')) { - var authData = this.get('authData') || {}; - if (typeof authData !== 'object') { - throw new Error('Invalid type: authData field should be an object'); - } - authData[authType] = options.authData; - - var controller = CoreManager.getUserController(); - return controller.linkWith(this, authData)._thenRunCallbacks(options, this); - } else { - var promise = new ParsePromise(); - provider.authenticate({ - success: (provider, result) => { - var opts = {}; - opts.authData = result; - if (options.success) { - opts.success = options.success; - } - if (options.error) { - opts.error = options.error; - } - this._linkWith(provider, opts).then(() => { - promise.resolve(this); - }, error => { - promise.reject(error); - }); - }, - error: (provider, error) => { - if (typeof options.error === 'function') { - options.error(this, error); - } - promise.reject(error); - } - }); - return promise; - } - } - - /** - * Synchronizes auth data for a provider (e.g. puts the access token in the - * right place to be used by the Facebook SDK). - * @method _synchronizeAuthData - */ - _synchronizeAuthData(provider) { - if (!this.isCurrent() || !provider) { - return; - } - var authType; - if (typeof provider === 'string') { - authType = provider; - provider = authProviders[authType]; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData'); - if (!provider || !authData || typeof authData !== 'object') { - return; - } - var success = provider.restoreAuthentication(authData[authType]); - if (!success) { - this._unlinkFrom(provider); - } - } - - /** - * Synchronizes authData for all providers. - * @method _synchronizeAllAuthData - */ - _synchronizeAllAuthData() { - var authData = this.get('authData'); - if (typeof authData !== 'object') { - return; - } - - for (var key in authData) { - this._synchronizeAuthData(key); - } - } - - /** - * Removes null values from authData (which exist temporarily for - * unlinking) - * @method _cleanupAuthData - */ - _cleanupAuthData() { - if (!this.isCurrent()) { - return; - } - var authData = this.get('authData'); - if (typeof authData !== 'object') { - return; - } - - for (var key in authData) { - if (!authData[key]) { - delete authData[key]; - } - } - } - - /** - * Unlinks a user from a service. - * @method _unlinkFrom - */ - _unlinkFrom(provider, options) { - if (typeof provider === 'string') { - provider = authProviders[provider]; - } else { - provider.getAuthType(); - } - return this._linkWith(provider, { authData: null }).then(() => { - this._synchronizeAuthData(provider); - return ParsePromise.as(this); - })._thenRunCallbacks(options); - } - - /** - * Checks whether a user is linked to a service. - * @method _isLinked - */ - _isLinked(provider) { - var authType; - if (typeof provider === 'string') { - authType = provider; - } else { - authType = provider.getAuthType(); - } - var authData = this.get('authData') || {}; - if (typeof authData !== 'object') { - return false; - } - return !!authData[authType]; - } - - /** - * Deauthenticates all providers. - * @method _logOutWithAll - */ - _logOutWithAll() { - var authData = this.get('authData'); - if (typeof authData !== 'object') { - return; - } - - for (var key in authData) { - this._logOutWith(key); - } - } - - /** - * Deauthenticates a single provider (e.g. removing access tokens from the - * Facebook SDK). - * @method _logOutWith - */ - _logOutWith(provider) { - if (!this.isCurrent()) { - return; - } - if (typeof provider === 'string') { - provider = authProviders[provider]; - } - if (provider && provider.deauthenticate) { - provider.deauthenticate(); - } - } - - /** - * Class instance method used to maintain specific keys when a fetch occurs. - * Used to ensure that the session token is not lost. - */ - _preserveFieldsOnFetch() { - return { - sessionToken: this.get('sessionToken') - }; - } - - /** - * Returns true if current would return this user. - * @method isCurrent - * @return {Boolean} - */ - isCurrent() { - var current = ParseUser.current(); - return !!current && current.id === this.id; - } - - /** - * Returns get("username"). - * @method getUsername - * @return {String} - */ - getUsername() { - const username = this.get('username'); - if (username == null || typeof username === 'string') { - return username; - } - return ''; - } - - /** - * Calls set("username", username, options) and returns the result. - * @method setUsername - * @param {String} username - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - setUsername(username) { - // Strip anonymity, even we do not support anonymous user in js SDK, we may - // encounter anonymous user created by android/iOS in cloud code. - var authData = this.get('authData'); - if (authData && typeof authData === 'object' && authData.hasOwnProperty('anonymous')) { - // We need to set anonymous to null instead of deleting it in order to remove it from Parse. - authData.anonymous = null; - } - this.set('username', username); - } - - /** - * Calls set("password", password, options) and returns the result. - * @method setPassword - * @param {String} password - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - setPassword(password) { - this.set('password', password); - } - - /** - * Returns get("email"). - * @method getEmail - * @return {String} - */ - getEmail() { - const email = this.get('email'); - if (email == null || typeof email === 'string') { - return email; - } - return ''; - } - - /** - * Calls set("email", email, options) and returns the result. - * @method setEmail - * @param {String} email - * @param {Object} options A Backbone-style options object. - * @return {Boolean} - */ - setEmail(email) { - this.set('email', email); - } - - /** - * Returns the session token for this user, if the user has been logged in, - * or if it is the result of a query with the master key. Otherwise, returns - * undefined. - * @method getSessionToken - * @return {String} the session token, or undefined - */ - getSessionToken() { - const token = this.get('sessionToken'); - if (token == null || typeof token === 'string') { - return token; - } - return ''; - } - - /** - * Checks whether this user is the current user and has been authenticated. - * @method authenticated - * @return (Boolean) whether this user is the current user and is logged in. - */ - authenticated() { - var current = ParseUser.current(); - return !!this.get('sessionToken') && !!current && current.id === this.id; - } - - /** - * Signs up a new user. You should call this instead of save for - * new Parse.Users. This will create a new Parse.User on the server, and - * also persist the session on disk so that you can access the user using - * current. - * - *

                              A username and password must be set before calling signUp.

                              - * - *

                              Calls options.success or options.error on completion.

                              - * - * @method signUp - * @param {Object} attrs Extra fields to set on the new user, or null. - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled when the signup - * finishes. - */ - signUp(attrs, options) { - options = options || {}; - - var signupOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - signupOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - signupOptions.installationId = options.installationId; - } - - var controller = CoreManager.getUserController(); - return controller.signUp(this, attrs, signupOptions)._thenRunCallbacks(options, this); - } - - /** - * Logs in a Parse.User. On success, this saves the session to disk, - * so you can retrieve the currently logged in user using - * current. - * - *

                              A username and password must be set before calling logIn.

                              - * - *

                              Calls options.success or options.error on completion.

                              - * - * @method logIn - * @param {Object} options A Backbone-style options object. - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login is complete. - */ - logIn(options) { - options = options || {}; - - var loginOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - loginOptions.useMasterKey = options.useMasterKey; - } - if (options.hasOwnProperty('installationId')) { - loginOptions.installationId = options.installationId; - } - - var controller = CoreManager.getUserController(); - return controller.logIn(this, loginOptions)._thenRunCallbacks(options, this); - } - - /** - * Wrap the default save behavior with functionality to save to local - * storage if this is current user. - */ - save(...args) { - return super.save.apply(this, args).then(() => { - if (this.isCurrent()) { - return CoreManager.getUserController().updateUserOnDisk(this); - } - return this; - }); - } - - /** - * Wrap the default destroy behavior with functionality that logs out - * the current user when it is destroyed - */ - destroy(...args) { - return super.destroy.apply(this, args).then(() => { - if (this.isCurrent()) { - return CoreManager.getUserController().removeUserFromDisk(); - } - return this; - }); - } - - /** - * Wrap the default fetch behavior with functionality to save to local - * storage if this is current user. - */ - fetch(...args) { - return super.fetch.apply(this, args).then(() => { - if (this.isCurrent()) { - return CoreManager.getUserController().updateUserOnDisk(this); - } - return this; - }); - } - - static readOnlyAttributes() { - return ['sessionToken']; - } - - /** - * Adds functionality to the existing Parse.User class - * @method extend - * @param {Object} protoProps A set of properties to add to the prototype - * @param {Object} classProps A set of static properties to add to the class - * @static - * @return {Class} The newly extended Parse.User class - */ - static extend(protoProps, classProps) { - if (protoProps) { - for (var prop in protoProps) { - if (prop !== 'className') { - Object.defineProperty(ParseUser.prototype, prop, { - value: protoProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - if (classProps) { - for (var prop in classProps) { - if (prop !== 'className') { - Object.defineProperty(ParseUser, prop, { - value: classProps[prop], - enumerable: false, - writable: true, - configurable: true - }); - } - } - } - - return ParseUser; - } - - /** - * Retrieves the currently logged in ParseUser with a valid session, - * either from memory or localStorage, if necessary. - * @method current - * @static - * @return {Parse.Object} The currently logged in Parse.User. - */ - static current() { - if (!canUseCurrentUser) { - return null; - } - var controller = CoreManager.getUserController(); - return controller.currentUser(); - } - - /** - * Retrieves the currently logged in ParseUser from asynchronous Storage. - * @method currentAsync - * @static - * @return {Parse.Promise} A Promise that is resolved with the currently - * logged in Parse User - */ - static currentAsync() { - if (!canUseCurrentUser) { - return ParsePromise.as(null); - } - var controller = CoreManager.getUserController(); - return controller.currentUserAsync(); - } - - /** - * Signs up a new user with a username (or email) and password. - * This will create a new Parse.User on the server, and also persist the - * session in localStorage so that you can access the user using - * {@link #current}. - * - *

                              Calls options.success or options.error on completion.

                              - * - * @method signUp - * @param {String} username The username (or email) to sign up with. - * @param {String} password The password to sign up with. - * @param {Object} attrs Extra fields to set on the new user. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the signup completes. - */ - static signUp(username, password, attrs, options) { - attrs = attrs || {}; - attrs.username = username; - attrs.password = password; - var user = new ParseUser(attrs); - return user.signUp({}, options); - } - - /** - * Logs in a user with a username (or email) and password. On success, this - * saves the session to disk, so you can retrieve the currently logged in - * user using current. - * - *

                              Calls options.success or options.error on completion.

                              - * - * @method logIn - * @param {String} username The username (or email) to log in with. - * @param {String} password The password to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - static logIn(username, password, options) { - if (typeof username !== 'string') { - return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); - } else if (typeof password !== 'string') { - return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Password must be a string.')); - } - var user = new ParseUser(); - user._finishFetch({ username: username, password: password }); - return user.logIn(options); - } - - /** - * Logs in a user with a session token. On success, this saves the session - * to disk, so you can retrieve the currently logged in user using - * current. - * - *

                              Calls options.success or options.error on completion.

                              - * - * @method become - * @param {String} sessionToken The sessionToken to log in with. - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is fulfilled with the user when - * the login completes. - */ - static become(sessionToken, options) { - if (!canUseCurrentUser) { - throw new Error('It is not memory-safe to become a user in a server environment'); - } - options = options || {}; - - var becomeOptions = { - sessionToken: sessionToken - }; - if (options.hasOwnProperty('useMasterKey')) { - becomeOptions.useMasterKey = options.useMasterKey; - } - - var controller = CoreManager.getUserController(); - return controller.become(becomeOptions)._thenRunCallbacks(options); - } - - static logInWith(provider, options) { - return ParseUser._logInWith(provider, options); - } - - /** - * Logs out the currently logged in user session. This will remove the - * session from disk, log out of linked services, and future calls to - * current will return null. - * @method logOut - * @static - * @return {Parse.Promise} A promise that is resolved when the session is - * destroyed on the server. - */ - static logOut() { - if (!canUseCurrentUser) { - throw new Error('There is no current user user on a node.js server environment.'); - } - - var controller = CoreManager.getUserController(); - return controller.logOut(); - } - - /** - * Requests a password reset email to be sent to the specified email address - * associated with the user account. This email allows the user to securely - * reset their password on the Parse site. - * - *

                              Calls options.success or options.error on completion.

                              - * - * @method requestPasswordReset - * @param {String} email The email address associated with the user that - * forgot their password. - * @param {Object} options A Backbone-style options object. - * @static - */ - static requestPasswordReset(email, options) { - options = options || {}; - - var requestOptions = {}; - if (options.hasOwnProperty('useMasterKey')) { - requestOptions.useMasterKey = options.useMasterKey; - } - - var controller = CoreManager.getUserController(); - return controller.requestPasswordReset(email, requestOptions)._thenRunCallbacks(options); - } - - /** - * Allow someone to define a custom User class without className - * being rewritten to _User. The default behavior is to rewrite - * User to _User for legacy reasons. This allows developers to - * override that behavior. - * - * @method allowCustomUserClass - * @param {Boolean} isAllowed Whether or not to allow custom User class - * @static - */ - static allowCustomUserClass(isAllowed) { - CoreManager.set('PERFORM_USER_REWRITE', !isAllowed); - } - - /** - * Allows a legacy application to start using revocable sessions. If the - * current session token is not revocable, a request will be made for a new, - * revocable session. - * It is not necessary to call this method from cloud code unless you are - * handling user signup or login from the server side. In a cloud code call, - * this function will not attempt to upgrade the current token. - * @method enableRevocableSession - * @param {Object} options A Backbone-style options object. - * @static - * @return {Parse.Promise} A promise that is resolved when the process has - * completed. If a replacement session token is requested, the promise - * will be resolved after a new token has been fetched. - */ - static enableRevocableSession(options) { - options = options || {}; - CoreManager.set('FORCE_REVOCABLE_SESSION', true); - if (canUseCurrentUser) { - var current = ParseUser.current(); - if (current) { - return current._upgradeToRevocableSession(options); - } - } - return ParsePromise.as()._thenRunCallbacks(options); - } - - /** - * Enables the use of become or the current user in a server - * environment. These features are disabled by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method enableUnsafeCurrentUser - * @static - */ - static enableUnsafeCurrentUser() { - canUseCurrentUser = true; - } - - /** - * Disables the use of become or the current user in any environment. - * These features are disabled on servers by default, since they depend on - * global objects that are not memory-safe for most servers. - * @method disableUnsafeCurrentUser - * @static - */ - static disableUnsafeCurrentUser() { - canUseCurrentUser = false; - } - - static _registerAuthenticationProvider(provider) { - authProviders[provider.getAuthType()] = provider; - // Synchronize the current user with the auth provider. - ParseUser.currentAsync().then(current => { - if (current) { - current._synchronizeAuthData(provider.getAuthType()); - } - }); - } - - static _logInWith(provider, options) { - var user = new ParseUser(); - return user._linkWith(provider, options); - } - - static _clearCache() { - currentUserCache = null; - currentUserCacheMatchesDisk = false; - } - - static _setCurrentUserCache(user) { - currentUserCache = user; - } -} - -ParseObject.registerSubclass('_User', ParseUser); - -var DefaultController = { - updateUserOnDisk(user) { - var path = Storage.generatePath(CURRENT_USER_KEY); - var json = user.toJSON(); - json.className = '_User'; - return Storage.setItemAsync(path, JSON.stringify(json)).then(() => { - return user; - }); - }, - - removeUserFromDisk() { - let path = Storage.generatePath(CURRENT_USER_KEY); - currentUserCacheMatchesDisk = true; - currentUserCache = null; - return Storage.removeItemAsync(path); - }, - - setCurrentUser(user) { - currentUserCache = user; - user._cleanupAuthData(); - user._synchronizeAllAuthData(); - return DefaultController.updateUserOnDisk(user); - }, - - currentUser() { - if (currentUserCache) { - return currentUserCache; - } - if (currentUserCacheMatchesDisk) { - return null; - } - if (Storage.async()) { - throw new Error('Cannot call currentUser() when using a platform with an async ' + 'storage system. Call currentUserAsync() instead.'); - } - var path = Storage.generatePath(CURRENT_USER_KEY); - var userData = Storage.getItem(path); - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return null; - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = ParseObject.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return current; - }, - - currentUserAsync() { - if (currentUserCache) { - return ParsePromise.as(currentUserCache); - } - if (currentUserCacheMatchesDisk) { - return ParsePromise.as(null); - } - var path = Storage.generatePath(CURRENT_USER_KEY); - return Storage.getItemAsync(path).then(userData => { - currentUserCacheMatchesDisk = true; - if (!userData) { - currentUserCache = null; - return ParsePromise.as(null); - } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; - } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; - } - delete userData._id; - } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; - } - var current = ParseObject.fromJSON(userData); - currentUserCache = current; - current._synchronizeAllAuthData(); - return ParsePromise.as(current); - }); - }, - - signUp(user, attrs, options) { - var username = attrs && attrs.username || user.get('username'); - var password = attrs && attrs.password || user.get('password'); - - if (!username || !username.length) { - return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Cannot sign up user with an empty name.')); - } - if (!password || !password.length) { - return ParsePromise.error(new ParseError(ParseError.OTHER_CAUSE, 'Cannot sign up user with an empty password.')); - } - - return user.save(attrs, options).then(() => { - // Clear the password field - user._finishFetch({ password: undefined }); - - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - }, - - logIn(user, options) { - var RESTController = CoreManager.getRESTController(); - var stateController = CoreManager.getObjectStateController(); - var auth = { - username: user.get('username'), - password: user.get('password') - }; - return RESTController.request('GET', 'login', auth, options).then((response, status) => { - user._migrateId(response.objectId); - user._setExisted(true); - stateController.setPendingOp(user._getStateIdentifier(), 'username', undefined); - stateController.setPendingOp(user._getStateIdentifier(), 'password', undefined); - response.password = undefined; - user._finishFetch(response); - if (!canUseCurrentUser) { - // We can't set the current user, so just return the one we logged in - return ParsePromise.as(user); - } - return DefaultController.setCurrentUser(user); - }); - }, - - become(options) { - var user = new ParseUser(); - var RESTController = CoreManager.getRESTController(); - return RESTController.request('GET', 'users/me', {}, options).then((response, status) => { - user._finishFetch(response); - user._setExisted(true); - return DefaultController.setCurrentUser(user); - }); - }, - - logOut() { - return DefaultController.currentUserAsync().then(currentUser => { - var path = Storage.generatePath(CURRENT_USER_KEY); - var promise = Storage.removeItemAsync(path); - var RESTController = CoreManager.getRESTController(); - if (currentUser !== null) { - var currentSession = currentUser.getSessionToken(); - if (currentSession && isRevocableSession(currentSession)) { - promise = promise.then(() => { - return RESTController.request('POST', 'logout', {}, { sessionToken: currentSession }); - }); - } - currentUser._logOutWithAll(); - currentUser._finishFetch({ sessionToken: undefined }); - } - currentUserCacheMatchesDisk = true; - currentUserCache = null; - - return promise; - }); - }, - - requestPasswordReset(email, options) { - var RESTController = CoreManager.getRESTController(); - return RESTController.request('POST', 'requestPasswordReset', { email: email }, options); - }, - - upgradeToRevocableSession(user, options) { - var token = user.getSessionToken(); - if (!token) { - return ParsePromise.error(new ParseError(ParseError.SESSION_MISSING, 'Cannot upgrade a user with no session token')); - } - - options.sessionToken = token; - - var RESTController = CoreManager.getRESTController(); - return RESTController.request('POST', 'upgradeToRevocableSession', {}, options).then(result => { - var session = new ParseSession(); - session._finishFetch(result); - user._finishFetch({ sessionToken: session.getSessionToken() }); - if (user.isCurrent()) { - return DefaultController.setCurrentUser(user); - } - return ParsePromise.as(user); - }); - }, - - linkWith(user, authData) { - return user.save({ authData }).then(() => { - if (canUseCurrentUser) { - return DefaultController.setCurrentUser(user); - } - return user; - }); - } -}; - -CoreManager.setUserController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/Push.js b/lib/react-native/Push.js deleted file mode 100644 index 2710abe4d..000000000 --- a/lib/react-native/Push.js +++ /dev/null @@ -1,77 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import ParseQuery from './ParseQuery'; - -/** - * Contains functions to deal with Push in Parse. - * @class Parse.Push - * @static - */ - -/** - * Sends a push notification. - * @method send - * @param {Object} data - The data of the push notification. Valid fields - * are: - *
                                - *
                              1. channels - An Array of channels to push to.
                              2. - *
                              3. push_time - A Date object for when to send the push.
                              4. - *
                              5. expiration_time - A Date object for when to expire - * the push.
                              6. - *
                              7. expiration_interval - The seconds from now to expire the push.
                              8. - *
                              9. where - A Parse.Query over Parse.Installation that is used to match - * a set of installations to push to.
                              10. - *
                              11. data - The data to send as part of the push
                              12. - *
                                  - * @param {Object} options An object that has an optional success function, - * that takes no arguments and will be called on a successful push, and - * an error function that takes a Parse.Error and will be called if the push - * failed. - * @return {Parse.Promise} A promise that is fulfilled when the push request - * completes. - */ -export function send(data, options) { - options = options || {}; - - if (data.where && data.where instanceof ParseQuery) { - data.where = data.where.toJSON().where; - } - - if (data.push_time && typeof data.push_time === 'object') { - data.push_time = data.push_time.toJSON(); - } - - if (data.expiration_time && typeof data.expiration_time === 'object') { - data.expiration_time = data.expiration_time.toJSON(); - } - - if (data.expiration_time && data.expiration_interval) { - throw new Error('expiration_time and expiration_interval cannot both be set.'); - } - - return CoreManager.getPushController().send(data, { - useMasterKey: options.useMasterKey - })._thenRunCallbacks(options); -} - -var DefaultController = { - send(data, options) { - var RESTController = CoreManager.getRESTController(); - - var request = RESTController.request('POST', 'push', data, { useMasterKey: !!options.useMasterKey }); - - return request._thenRunCallbacks(options); - } -}; - -CoreManager.setPushController(DefaultController); \ No newline at end of file diff --git a/lib/react-native/RESTController.js b/lib/react-native/RESTController.js deleted file mode 100644 index 89ee421a0..000000000 --- a/lib/react-native/RESTController.js +++ /dev/null @@ -1,226 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import ParseError from './ParseError'; -import ParsePromise from './ParsePromise'; -import Storage from './Storage'; - -var XHR = null; -if (typeof XMLHttpRequest !== 'undefined') { - XHR = XMLHttpRequest; -} - - -var useXDomainRequest = false; -if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) { - useXDomainRequest = true; -} - -function ajaxIE9(method, url, data) { - var promise = new ParsePromise(); - var xdr = new XDomainRequest(); - xdr.onload = function () { - var response; - try { - response = JSON.parse(xdr.responseText); - } catch (e) { - promise.reject(e); - } - if (response) { - promise.resolve(response); - } - }; - xdr.onerror = xdr.ontimeout = function () { - // Let's fake a real error message. - var fakeResponse = { - responseText: JSON.stringify({ - code: ParseError.X_DOMAIN_REQUEST, - error: 'IE\'s XDomainRequest does not supply error info.' - }) - }; - promise.reject(fakeResponse); - }; - xdr.onprogress = function () {}; - xdr.open(method, url); - xdr.send(data); - return promise; -} - -const RESTController = { - ajax(method, url, data, headers) { - if (useXDomainRequest) { - return ajaxIE9(method, url, data, headers); - } - - var promise = new ParsePromise(); - var attempts = 0; - - var dispatch = function () { - if (XHR == null) { - throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.'); - } - var handled = false; - var xhr = new XHR(); - - xhr.onreadystatechange = function () { - if (xhr.readyState !== 4 || handled) { - return; - } - handled = true; - - if (xhr.status >= 200 && xhr.status < 300) { - var response; - try { - response = JSON.parse(xhr.responseText); - } catch (e) { - promise.reject(e.toString()); - } - if (response) { - promise.resolve(response, xhr.status, xhr); - } - } else if (xhr.status >= 500 || xhr.status === 0) { - // retry on 5XX or node-xmlhttprequest error - if (++attempts < CoreManager.get('REQUEST_ATTEMPT_LIMIT')) { - // Exponentially-growing random delay - var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts)); - setTimeout(dispatch, delay); - } else if (xhr.status === 0) { - promise.reject('Unable to connect to the Parse API'); - } else { - // After the retry limit is reached, fail - promise.reject(xhr); - } - } else { - promise.reject(xhr); - } - }; - - headers = headers || {}; - if (typeof headers['Content-Type'] !== 'string') { - headers['Content-Type'] = 'text/plain'; // Avoid pre-flight - } - if (CoreManager.get('IS_NODE')) { - headers['User-Agent'] = 'Parse/' + CoreManager.get('VERSION') + ' (NodeJS ' + process.versions.node + ')'; - } - - xhr.open(method, url, true); - for (var h in headers) { - xhr.setRequestHeader(h, headers[h]); - } - xhr.send(data); - }; - dispatch(); - - return promise; - }, - - request(method, path, data, options) { - options = options || {}; - var url = CoreManager.get('SERVER_URL'); - if (url[url.length - 1] !== '/') { - url += '/'; - } - url += path; - - var payload = {}; - if (data && typeof data === 'object') { - for (var k in data) { - payload[k] = data[k]; - } - } - - if (method !== 'POST') { - payload._method = method; - method = 'POST'; - } - - payload._ApplicationId = CoreManager.get('APPLICATION_ID'); - let jsKey = CoreManager.get('JAVASCRIPT_KEY'); - if (jsKey) { - payload._JavaScriptKey = jsKey; - } - payload._ClientVersion = CoreManager.get('VERSION'); - - var useMasterKey = options.useMasterKey; - if (typeof useMasterKey === 'undefined') { - useMasterKey = CoreManager.get('USE_MASTER_KEY'); - } - if (useMasterKey) { - if (CoreManager.get('MASTER_KEY')) { - delete payload._JavaScriptKey; - payload._MasterKey = CoreManager.get('MASTER_KEY'); - } else { - throw new Error('Cannot use the Master Key, it has not been provided.'); - } - } - - if (CoreManager.get('FORCE_REVOCABLE_SESSION')) { - payload._RevocableSession = '1'; - } - - var installationId = options.installationId; - var installationIdPromise; - if (installationId && typeof installationId === 'string') { - installationIdPromise = ParsePromise.as(installationId); - } else { - var installationController = CoreManager.getInstallationController(); - installationIdPromise = installationController.currentInstallationId(); - } - - return installationIdPromise.then(iid => { - payload._InstallationId = iid; - var userController = CoreManager.getUserController(); - if (options && typeof options.sessionToken === 'string') { - return ParsePromise.as(options.sessionToken); - } else if (userController) { - return userController.currentUserAsync().then(user => { - if (user) { - return ParsePromise.as(user.getSessionToken()); - } - return ParsePromise.as(null); - }); - } - return ParsePromise.as(null); - }).then(token => { - if (token) { - payload._SessionToken = token; - } - - var payloadString = JSON.stringify(payload); - - return RESTController.ajax(method, url, payloadString); - }).then(null, function (response) { - // Transform the error into an instance of ParseError by trying to parse - // the error string as JSON - var error; - if (response && response.responseText) { - try { - var errorJSON = JSON.parse(response.responseText); - error = new ParseError(errorJSON.code, errorJSON.error); - } catch (e) { - // If we fail to parse the error text, that's okay. - error = new ParseError(ParseError.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText); - } - } else { - error = new ParseError(ParseError.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + JSON.stringify(response)); - } - - return ParsePromise.error(error); - }); - }, - - _setXHR(xhr) { - XHR = xhr; - } -}; - -module.exports = RESTController; \ No newline at end of file diff --git a/lib/react-native/SingleInstanceStateController.js b/lib/react-native/SingleInstanceStateController.js deleted file mode 100644 index 2f57854d7..000000000 --- a/lib/react-native/SingleInstanceStateController.js +++ /dev/null @@ -1,125 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import * as ObjectStateMutations from './ObjectStateMutations'; - -let objectState = {}; - -export function getState(obj) { - let classData = objectState[obj.className]; - if (classData) { - return classData[obj.id] || null; - } - return null; -} - -export function initializeState(obj, initial) { - let state = getState(obj); - if (state) { - return state; - } - if (!objectState[obj.className]) { - objectState[obj.className] = {}; - } - if (!initial) { - initial = ObjectStateMutations.defaultState(); - } - state = objectState[obj.className][obj.id] = initial; - return state; -} - -export function removeState(obj) { - let state = getState(obj); - if (state === null) { - return null; - } - delete objectState[obj.className][obj.id]; - return state; -} - -export function getServerData(obj) { - let state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -export function setServerData(obj, attributes) { - let serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -export function getPendingOps(obj) { - let state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -export function setPendingOp(obj, attr, op) { - let pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -export function pushPendingState(obj) { - let pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -export function popPendingState(obj) { - let pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -export function mergeFirstPendingState(obj) { - let pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -export function getObjectCache(obj) { - let state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -export function estimateAttribute(obj, attr) { - let serverData = getServerData(obj); - let pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -export function estimateAttributes(obj) { - let serverData = getServerData(obj); - let pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -export function commitServerChanges(obj, changes) { - let state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -export function enqueueTask(obj, task) { - let state = initializeState(obj); - return state.tasks.enqueue(task); -} - -export function clearAllState() { - objectState = {}; -} - -export function duplicateState(source, dest) { - dest.id = source.id; -} \ No newline at end of file diff --git a/lib/react-native/Storage.js b/lib/react-native/Storage.js deleted file mode 100644 index 2bfa47412..000000000 --- a/lib/react-native/Storage.js +++ /dev/null @@ -1,92 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import CoreManager from './CoreManager'; -import ParsePromise from './ParsePromise'; - -var Storage = { - async() { - var controller = CoreManager.getStorageController(); - return !!controller.async; - }, - - getItem(path) { - var controller = CoreManager.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.getItem(path); - }, - - getItemAsync(path) { - var controller = CoreManager.getStorageController(); - if (controller.async === 1) { - return controller.getItemAsync(path); - } - return ParsePromise.as(controller.getItem(path)); - }, - - setItem(path, value) { - var controller = CoreManager.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.setItem(path, value); - }, - - setItemAsync(path, value) { - var controller = CoreManager.getStorageController(); - if (controller.async === 1) { - return controller.setItemAsync(path, value); - } - return ParsePromise.as(controller.setItem(path, value)); - }, - - removeItem(path) { - var controller = CoreManager.getStorageController(); - if (controller.async === 1) { - throw new Error('Synchronous storage is not supported by the current storage controller'); - } - return controller.removeItem(path); - }, - - removeItemAsync(path) { - var controller = CoreManager.getStorageController(); - if (controller.async === 1) { - return controller.removeItemAsync(path); - } - return ParsePromise.as(controller.removeItem(path)); - }, - - generatePath(path) { - if (!CoreManager.get('APPLICATION_ID')) { - throw new Error('You need to call Parse.initialize before using Parse.'); - } - if (typeof path !== 'string') { - throw new Error('Tried to get a Storage path that was not a String.'); - } - if (path[0] === '/') { - path = path.substr(1); - } - return 'Parse/' + CoreManager.get('APPLICATION_ID') + '/' + path; - }, - - _clear() { - var controller = CoreManager.getStorageController(); - if (controller.hasOwnProperty('clear')) { - controller.clear(); - } - } -}; - -module.exports = Storage; - -CoreManager.setStorageController(require('./StorageController.react-native')); \ No newline at end of file diff --git a/lib/react-native/StorageController.browser.js b/lib/react-native/StorageController.browser.js deleted file mode 100644 index 84af3ccee..000000000 --- a/lib/react-native/StorageController.browser.js +++ /dev/null @@ -1,38 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParsePromise from './ParsePromise'; - -var StorageController = { - async: 0, - - getItem(path) { - return localStorage.getItem(path); - }, - - setItem(path, value) { - try { - localStorage.setItem(path, value); - } catch (e) { - // Quota exceeded, possibly due to Safari Private Browsing mode - } - }, - - removeItem(path) { - localStorage.removeItem(path); - }, - - clear() { - localStorage.clear(); - } -}; - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/react-native/StorageController.default.js b/lib/react-native/StorageController.default.js deleted file mode 100644 index ded857850..000000000 --- a/lib/react-native/StorageController.default.js +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -// When there is no native storage interface, we default to an in-memory map -var memMap = {}; -var StorageController = { - async: 0, - - getItem(path) { - if (memMap.hasOwnProperty(path)) { - return memMap[path]; - } - return null; - }, - - setItem(path, value) { - memMap[path] = String(value); - }, - - removeItem(path) { - delete memMap[path]; - }, - - clear() { - for (var key in memMap) { - if (memMap.hasOwnProperty(key)) { - delete memMap[key]; - } - } - } -}; - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/react-native/StorageController.react-native.js b/lib/react-native/StorageController.react-native.js deleted file mode 100644 index 68e04d768..000000000 --- a/lib/react-native/StorageController.react-native.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParsePromise from './ParsePromise'; -// RN packager nonsense -import { AsyncStorage } from 'react-native/Libraries/react-native/react-native.js'; - -var StorageController = { - async: 1, - - getItemAsync(path) { - var p = new ParsePromise(); - AsyncStorage.getItem(path, function (err, value) { - if (err) { - p.reject(err); - } else { - p.resolve(value); - } - }); - return p; - }, - - setItemAsync(path, value) { - var p = new ParsePromise(); - AsyncStorage.setItem(path, value, function (err) { - if (err) { - p.reject(err); - } else { - p.resolve(value); - } - }); - return p; - }, - - removeItemAsync(path) { - var p = new ParsePromise(); - AsyncStorage.removeItem(path, function (err) { - if (err) { - p.reject(err); - } else { - p.resolve(); - } - }); - return p; - }, - - clear() { - AsyncStorage.clear(); - } -}; - -module.exports = StorageController; \ No newline at end of file diff --git a/lib/react-native/TaskQueue.js b/lib/react-native/TaskQueue.js deleted file mode 100644 index 584168339..000000000 --- a/lib/react-native/TaskQueue.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParsePromise from './ParsePromise'; - -class TaskQueue { - - constructor() { - this.queue = []; - } - - enqueue(task) { - var taskComplete = new ParsePromise(); - this.queue.push({ - task: task, - _completion: taskComplete - }); - if (this.queue.length === 1) { - task().then(() => { - this._dequeue(); - taskComplete.resolve(); - }, error => { - this._dequeue(); - taskComplete.reject(error); - }); - } - return taskComplete; - } - - _dequeue() { - this.queue.shift(); - if (this.queue.length) { - var next = this.queue[0]; - next.task().then(() => { - this._dequeue(); - next._completion.resolve(); - }, error => { - this._dequeue(); - next._completion.reject(error); - }); - } - } -} - -module.exports = TaskQueue; \ No newline at end of file diff --git a/lib/react-native/UniqueInstanceStateController.js b/lib/react-native/UniqueInstanceStateController.js deleted file mode 100644 index 2b112e228..000000000 --- a/lib/react-native/UniqueInstanceStateController.js +++ /dev/null @@ -1,140 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import * as ObjectStateMutations from './ObjectStateMutations'; -import TaskQueue from './TaskQueue'; - -let objectState = new WeakMap(); - -export function getState(obj) { - let classData = objectState.get(obj); - return classData || null; -} - -export function initializeState(obj, initial) { - let state = getState(obj); - if (state) { - return state; - } - if (!initial) { - initial = { - serverData: {}, - pendingOps: [{}], - objectCache: {}, - tasks: new TaskQueue(), - existed: false - }; - } - state = initial; - objectState.set(obj, state); - return state; -} - -export function removeState(obj) { - let state = getState(obj); - if (state === null) { - return null; - } - objectState.delete(obj); - return state; -} - -export function getServerData(obj) { - let state = getState(obj); - if (state) { - return state.serverData; - } - return {}; -} - -export function setServerData(obj, attributes) { - let serverData = initializeState(obj).serverData; - ObjectStateMutations.setServerData(serverData, attributes); -} - -export function getPendingOps(obj) { - let state = getState(obj); - if (state) { - return state.pendingOps; - } - return [{}]; -} - -export function setPendingOp(obj, attr, op) { - let pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.setPendingOp(pendingOps, attr, op); -} - -export function pushPendingState(obj) { - let pendingOps = initializeState(obj).pendingOps; - ObjectStateMutations.pushPendingState(pendingOps); -} - -export function popPendingState(obj) { - let pendingOps = initializeState(obj).pendingOps; - return ObjectStateMutations.popPendingState(pendingOps); -} - -export function mergeFirstPendingState(obj) { - let pendingOps = getPendingOps(obj); - ObjectStateMutations.mergeFirstPendingState(pendingOps); -} - -export function getObjectCache(obj) { - let state = getState(obj); - if (state) { - return state.objectCache; - } - return {}; -} - -export function estimateAttribute(obj, attr) { - let serverData = getServerData(obj); - let pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttribute(serverData, pendingOps, obj.className, obj.id, attr); -} - -export function estimateAttributes(obj) { - let serverData = getServerData(obj); - let pendingOps = getPendingOps(obj); - return ObjectStateMutations.estimateAttributes(serverData, pendingOps, obj.className, obj.id); -} - -export function commitServerChanges(obj, changes) { - let state = initializeState(obj); - ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes); -} - -export function enqueueTask(obj, task) { - let state = initializeState(obj); - return state.tasks.enqueue(task); -} - -export function duplicateState(source, dest) { - let oldState = initializeState(source); - let newState = initializeState(dest); - for (let key in oldState.serverData) { - newState.serverData[key] = oldState.serverData[key]; - } - for (let index = 0; index < oldState.pendingOps.length; index++) { - for (let key in oldState.pendingOps[index]) { - newState.pendingOps[index][key] = oldState.pendingOps[index][key]; - } - } - for (let key in oldState.objectCache) { - newState.objectCache[key] = oldState.objectCache[key]; - } - newState.existed = oldState.existed; -} - -export function clearAllState() { - objectState = new WeakMap(); -} \ No newline at end of file diff --git a/lib/react-native/arrayContainsObject.js b/lib/react-native/arrayContainsObject.js deleted file mode 100644 index 153c7320b..000000000 --- a/lib/react-native/arrayContainsObject.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseObject from './ParseObject'; - -export default function arrayContainsObject(array, object) { - if (array.indexOf(object) > -1) { - return true; - } - for (var i = 0; i < array.length; i++) { - if (array[i] instanceof ParseObject && array[i].className === object.className && array[i]._getId() === object._getId()) { - return true; - } - } - return false; -} \ No newline at end of file diff --git a/lib/react-native/canBeSerialized.js b/lib/react-native/canBeSerialized.js deleted file mode 100644 index b696d8028..000000000 --- a/lib/react-native/canBeSerialized.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseFile from './ParseFile'; -import ParseObject from './ParseObject'; -import ParseRelation from './ParseRelation'; - -export default function canBeSerialized(obj) { - if (!(obj instanceof ParseObject)) { - return true; - } - var attributes = obj.attributes; - for (var attr in attributes) { - var val = attributes[attr]; - if (!canBeSerializedHelper(val)) { - return false; - } - } - return true; -} - -function canBeSerializedHelper(value) { - if (typeof value !== 'object') { - return true; - } - if (value instanceof ParseRelation) { - return true; - } - if (value instanceof ParseObject) { - return !!value.id; - } - if (value instanceof ParseFile) { - if (value.url()) { - return true; - } - return false; - } - if (Array.isArray(value)) { - for (var i = 0; i < value.length; i++) { - if (!canBeSerializedHelper(value[i])) { - return false; - } - } - return true; - } - for (var k in value) { - if (!canBeSerializedHelper(value[k])) { - return false; - } - } - return true; -} \ No newline at end of file diff --git a/lib/react-native/decode.js b/lib/react-native/decode.js deleted file mode 100644 index 9863da760..000000000 --- a/lib/react-native/decode.js +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseACL from './ParseACL'; -import ParseFile from './ParseFile'; -import ParseGeoPoint from './ParseGeoPoint'; -import ParseObject from './ParseObject'; -import { opFromJSON } from './ParseOp'; -import ParseRelation from './ParseRelation'; - -export default function decode(value) { - if (value === null || typeof value !== 'object') { - return value; - } - if (Array.isArray(value)) { - var dup = []; - value.forEach((v, i) => { - dup[i] = decode(v); - }); - return dup; - } - if (typeof value.__op === 'string') { - return opFromJSON(value); - } - if (value.__type === 'Pointer' && value.className) { - return ParseObject.fromJSON(value); - } - if (value.__type === 'Object' && value.className) { - return ParseObject.fromJSON(value); - } - if (value.__type === 'Relation') { - // The parent and key fields will be populated by the parent - var relation = new ParseRelation(null, null); - relation.targetClassName = value.className; - return relation; - } - if (value.__type === 'Date') { - return new Date(value.iso); - } - if (value.__type === 'File') { - return ParseFile.fromJSON(value); - } - if (value.__type === 'GeoPoint') { - return new ParseGeoPoint({ - latitude: value.latitude, - longitude: value.longitude - }); - } - var copy = {}; - for (var k in value) { - copy[k] = decode(value[k]); - } - return copy; -} \ No newline at end of file diff --git a/lib/react-native/encode.js b/lib/react-native/encode.js deleted file mode 100644 index 74a925352..000000000 --- a/lib/react-native/encode.js +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseACL from './ParseACL'; -import ParseFile from './ParseFile'; -import ParseGeoPoint from './ParseGeoPoint'; -import ParseObject from './ParseObject'; -import { Op } from './ParseOp'; -import ParseRelation from './ParseRelation'; - -var toString = Object.prototype.toString; - -function encode(value, disallowObjects, forcePointers, seen) { - if (value instanceof ParseObject) { - if (disallowObjects) { - throw new Error('Parse Objects not allowed here'); - } - var seenEntry = value.id ? value.className + ':' + value.id : value; - if (forcePointers || !seen || seen.indexOf(seenEntry) > -1 || value.dirty() || Object.keys(value._getServerData()).length < 1) { - return value.toPointer(); - } - seen = seen.concat(seenEntry); - return value._toFullJSON(seen); - } - if (value instanceof Op || value instanceof ParseACL || value instanceof ParseGeoPoint || value instanceof ParseRelation) { - return value.toJSON(); - } - if (value instanceof ParseFile) { - if (!value.url()) { - throw new Error('Tried to encode an unsaved file.'); - } - return value.toJSON(); - } - if (toString.call(value) === '[object Date]') { - if (isNaN(value)) { - throw new Error('Tried to encode an invalid date.'); - } - return { __type: 'Date', iso: value.toJSON() }; - } - if (toString.call(value) === '[object RegExp]' && typeof value.source === 'string') { - return value.source; - } - - if (Array.isArray(value)) { - return value.map(v => { - return encode(v, disallowObjects, forcePointers, seen); - }); - } - - if (value && typeof value === 'object') { - var output = {}; - for (var k in value) { - output[k] = encode(value[k], disallowObjects, forcePointers, seen); - } - return output; - } - - return value; -} - -export default function (value, disallowObjects, forcePointers, seen) { - return encode(value, !!disallowObjects, !!forcePointers, seen || []); -} \ No newline at end of file diff --git a/lib/react-native/equals.js b/lib/react-native/equals.js deleted file mode 100644 index 06ff31f3c..000000000 --- a/lib/react-native/equals.js +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -import ParseACL from './ParseACL'; -import ParseFile from './ParseFile'; -import ParseGeoPoint from './ParseGeoPoint'; -import ParseObject from './ParseObject'; - -export default function equals(a, b) { - if (typeof a !== typeof b) { - return false; - } - - if (!a || typeof a !== 'object') { - // a is a primitive - return a === b; - } - - if (Array.isArray(a) || Array.isArray(b)) { - if (!Array.isArray(a) || !Array.isArray(b)) { - return false; - } - if (a.length !== b.length) { - return false; - } - for (var i = a.length; i--;) { - if (!equals(a[i], b[i])) { - return false; - } - } - return true; - } - - if (a instanceof ParseACL || a instanceof ParseFile || a instanceof ParseGeoPoint || a instanceof ParseObject) { - return a.equals(b); - } - - if (Object.keys(a).length !== Object.keys(b).length) { - return false; - } - for (var k in a) { - if (!equals(a[k], b[k])) { - return false; - } - } - return true; -} \ No newline at end of file diff --git a/lib/react-native/escape.js b/lib/react-native/escape.js deleted file mode 100644 index e094f0747..000000000 --- a/lib/react-native/escape.js +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -var encoded = { - '&': '&', - '<': '<', - '>': '>', - '/': '/', - '\'': ''', - '"': '"' -}; - -export default function escape(str) { - return str.replace(/[&<>\/'"]/g, function (char) { - return encoded[char]; - }); -} \ No newline at end of file diff --git a/lib/react-native/isRevocableSession.js b/lib/react-native/isRevocableSession.js deleted file mode 100644 index 967341a57..000000000 --- a/lib/react-native/isRevocableSession.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -export default function isRevocableSession(token) { - return token.indexOf('r:') > -1; -} \ No newline at end of file diff --git a/lib/react-native/parseDate.js b/lib/react-native/parseDate.js deleted file mode 100644 index fe7538e41..000000000 --- a/lib/react-native/parseDate.js +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -export default function parseDate(iso8601) { - var regexp = new RegExp('^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' + 'T' + '([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2})' + '(.([0-9]+))?' + 'Z$'); - var match = regexp.exec(iso8601); - if (!match) { - return null; - } - - var year = match[1] || 0; - var month = (match[2] || 1) - 1; - var day = match[3] || 0; - var hour = match[4] || 0; - var minute = match[5] || 0; - var second = match[6] || 0; - var milli = match[8] || 0; - - return new Date(Date.UTC(year, month, day, hour, minute, second, milli)); -} \ No newline at end of file diff --git a/lib/react-native/unique.js b/lib/react-native/unique.js deleted file mode 100644 index c3d1e6364..000000000 --- a/lib/react-native/unique.js +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import arrayContainsObject from './arrayContainsObject'; -import ParseObject from './ParseObject'; - -export default function unique(arr) { - var uniques = []; - arr.forEach(value => { - if (value instanceof ParseObject) { - if (!arrayContainsObject(uniques, value)) { - uniques.push(value); - } - } else { - if (uniques.indexOf(value) < 0) { - uniques.push(value); - } - } - }); - return uniques; -} \ No newline at end of file diff --git a/lib/react-native/unsavedChildren.js b/lib/react-native/unsavedChildren.js deleted file mode 100644 index 5b71deea0..000000000 --- a/lib/react-native/unsavedChildren.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * Copyright (c) 2015-present, Parse, LLC. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - * - * - */ - -import ParseFile from './ParseFile'; -import ParseObject from './ParseObject'; -import ParseRelation from './ParseRelation'; - -/** - * Return an array of unsaved children, which are either Parse Objects or Files. - * If it encounters any dirty Objects without Ids, it will throw an exception. - */ -export default function unsavedChildren(obj, allowDeepUnsaved) { - var encountered = { - objects: {}, - files: [] - }; - var identifier = obj.className + ':' + obj._getId(); - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if (typeof attributes[attr] === 'object') { - traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); - } - } - var unsaved = []; - for (var id in encountered.objects) { - if (id !== identifier && encountered.objects[id] !== true) { - unsaved.push(encountered.objects[id]); - } - } - return unsaved.concat(encountered.files); -} - -function traverse(obj, encountered, shouldThrow, allowDeepUnsaved) { - if (obj instanceof ParseObject) { - if (!obj.id && shouldThrow) { - throw new Error('Cannot create a pointer to an unsaved Object.'); - } - var identifier = obj.className + ':' + obj._getId(); - if (!encountered.objects[identifier]) { - encountered.objects[identifier] = obj.dirty() ? obj : true; - var attributes = obj.attributes; - for (var attr in attributes) { - if (typeof attributes[attr] === 'object') { - traverse(attributes[attr], encountered, !allowDeepUnsaved, allowDeepUnsaved); - } - } - } - return; - } - if (obj instanceof ParseFile) { - if (!obj.url() && encountered.files.indexOf(obj) < 0) { - encountered.files.push(obj); - } - return; - } - if (obj instanceof ParseRelation) { - return; - } - if (Array.isArray(obj)) { - obj.forEach(el => { - if (typeof el === 'object') { - traverse(el, encountered, shouldThrow, allowDeepUnsaved); - } - }); - } - for (var k in obj) { - if (typeof obj[k] === 'object') { - traverse(obj[k], encountered, shouldThrow, allowDeepUnsaved); - } - } -} \ No newline at end of file