parse
Version:
Parse JavaScript SDK
1,540 lines • 2.03 MB
JavaScript
(function(factory) {
typeof define === "function" && define.amd ? define(factory) : factory();
})(function() {
"use strict";
function _mergeNamespaces(n, m) {
for (var i2 = 0; i2 < m.length; i2++) {
const e = m[i2];
if (typeof e !== "string" && !Array.isArray(e)) {
for (const k in e) {
if (k !== "default" && !(k in n)) {
const d = Object.getOwnPropertyDescriptor(e, k);
if (d) {
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
}
}
return Object.freeze(Object.defineProperty(n, Symbol.toStringTag, { value: "Module" }));
}
function getDefaultExportFromCjs$1(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
var browser$d = { exports: {} };
var process = browser$d.exports = {};
var cachedSetTimeout;
var cachedClearTimeout;
function defaultSetTimout() {
throw new Error("setTimeout has not been defined");
}
function defaultClearTimeout() {
throw new Error("clearTimeout has not been defined");
}
(function() {
try {
if (typeof setTimeout === "function") {
cachedSetTimeout = setTimeout;
} else {
cachedSetTimeout = defaultSetTimout;
}
} catch (e) {
cachedSetTimeout = defaultSetTimout;
}
try {
if (typeof clearTimeout === "function") {
cachedClearTimeout = clearTimeout;
} else {
cachedClearTimeout = defaultClearTimeout;
}
} catch (e) {
cachedClearTimeout = defaultClearTimeout;
}
})();
function runTimeout(fun) {
if (cachedSetTimeout === setTimeout) {
return setTimeout(fun, 0);
}
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
cachedSetTimeout = setTimeout;
return setTimeout(fun, 0);
}
try {
return cachedSetTimeout(fun, 0);
} catch (e) {
try {
return cachedSetTimeout.call(null, fun, 0);
} catch (e2) {
return cachedSetTimeout.call(this, fun, 0);
}
}
}
function runClearTimeout(marker) {
if (cachedClearTimeout === clearTimeout) {
return clearTimeout(marker);
}
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
cachedClearTimeout = clearTimeout;
return clearTimeout(marker);
}
try {
return cachedClearTimeout(marker);
} catch (e) {
try {
return cachedClearTimeout.call(null, marker);
} catch (e2) {
return cachedClearTimeout.call(this, marker);
}
}
}
var queue = [];
var draining = false;
var currentQueue;
var queueIndex = -1;
function cleanUpNextTick() {
if (!draining || !currentQueue) {
return;
}
draining = false;
if (currentQueue.length) {
queue = currentQueue.concat(queue);
} else {
queueIndex = -1;
}
if (queue.length) {
drainQueue();
}
}
function drainQueue() {
if (draining) {
return;
}
var timeout = runTimeout(cleanUpNextTick);
draining = true;
var len2 = queue.length;
while (len2) {
currentQueue = queue;
queue = [];
while (++queueIndex < len2) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len2 = queue.length;
}
currentQueue = null;
draining = false;
runClearTimeout(timeout);
}
process.nextTick = function(fun) {
var args = new Array(arguments.length - 1);
if (arguments.length > 1) {
for (var i2 = 1; i2 < arguments.length; i2++) {
args[i2 - 1] = arguments[i2];
}
}
queue.push(new Item(fun, args));
if (queue.length === 1 && !draining) {
runTimeout(drainQueue);
}
};
function Item(fun, array) {
this.fun = fun;
this.array = array;
}
Item.prototype.run = function() {
this.fun.apply(null, this.array);
};
process.title = "browser";
process.browser = true;
process.env = {};
process.argv = [];
process.version = "";
process.versions = {};
function noop() {
}
process.on = noop;
process.addListener = noop;
process.once = noop;
process.off = noop;
process.removeListener = noop;
process.removeAllListeners = noop;
process.emit = noop;
process.prependListener = noop;
process.prependOnceListener = noop;
process.listeners = function(name) {
return [];
};
process.binding = function(name) {
throw new Error("process.binding is not supported");
};
process.cwd = function() {
return "/";
};
process.chdir = function(dir) {
throw new Error("process.chdir is not supported");
};
process.umask = function() {
return 0;
};
var browserExports$1 = browser$d.exports;
const process$1 = /* @__PURE__ */ getDefaultExportFromCjs$1(browserExports$1);
const config = {
IS_NODE: typeof process$1 !== "undefined" && !!process$1.versions && !!process$1.versions.node && !process$1.versions.electron,
REQUEST_ATTEMPT_LIMIT: 5,
REQUEST_BATCH_SIZE: 20,
REQUEST_HEADERS: {},
SERVER_URL: "https://api.parse.com/1",
LIVEQUERY_SERVER_URL: null,
ENCRYPTED_KEY: null,
VERSION: "js8.0.0",
APPLICATION_ID: null,
JAVASCRIPT_KEY: null,
MAINTENANCE_KEY: null,
MASTER_KEY: null,
USE_MASTER_KEY: false,
PERFORM_USER_REWRITE: true,
FORCE_REVOCABLE_SESSION: false,
ENCRYPTED_USER: false,
IDEMPOTENCY: false,
ALLOW_CUSTOM_OBJECT_ID: false,
PARSE_ERRORS: [],
NODE_LOGGING: false
};
function requireMethods(name, methods, controller) {
methods.forEach((func) => {
if (typeof controller[func] !== "function") {
throw new Error(`${name} must implement ${func}()`);
}
});
}
const CoreManager = {
get: function(key2) {
if (Object.hasOwn(config, key2)) {
return config[key2];
}
throw new Error("Configuration key not found: " + key2);
},
set: function(key2, value) {
config[key2] = value;
},
setIfNeeded: function(key2, value) {
if (!Object.hasOwn(config, key2)) {
config[key2] = value;
}
return config[key2];
},
/* Specialized Controller Setters/Getters */
setAnalyticsController(controller) {
requireMethods("AnalyticsController", ["track"], controller);
config["AnalyticsController"] = controller;
},
getAnalyticsController() {
return config["AnalyticsController"];
},
setCloudController(controller) {
requireMethods("CloudController", ["run", "getJobsData", "startJob"], controller);
config["CloudController"] = controller;
},
getCloudController() {
return config["CloudController"];
},
setConfigController(controller) {
requireMethods("ConfigController", ["current", "get", "save"], controller);
config["ConfigController"] = controller;
},
getConfigController() {
return config["ConfigController"];
},
setCryptoController(controller) {
requireMethods("CryptoController", ["encrypt", "decrypt"], controller);
config["CryptoController"] = controller;
},
getCryptoController() {
return config["CryptoController"];
},
setEventEmitter(eventEmitter) {
config["EventEmitter"] = eventEmitter;
},
getEventEmitter() {
return config["EventEmitter"];
},
setFileController(controller) {
requireMethods("FileController", ["saveFile", "saveBase64"], controller);
config["FileController"] = controller;
},
setEventuallyQueue(controller) {
requireMethods("EventuallyQueue", ["poll", "save", "destroy"], controller);
config["EventuallyQueue"] = controller;
},
getEventuallyQueue() {
return config["EventuallyQueue"];
},
getFileController() {
return config["FileController"];
},
setInstallationController(controller) {
requireMethods(
"InstallationController",
["currentInstallationId", "currentInstallation", "updateInstallationOnDisk"],
controller
);
config["InstallationController"] = controller;
},
getInstallationController() {
return config["InstallationController"];
},
setLiveQuery(liveQuery) {
config["LiveQuery"] = liveQuery;
},
getLiveQuery() {
return config["LiveQuery"];
},
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", "aggregate"], controller);
config["QueryController"] = controller;
},
getQueryController() {
return config["QueryController"];
},
setRESTController(controller) {
requireMethods("RESTController", ["request", "ajax"], controller);
config["RESTController"] = controller;
},
getRESTController() {
return config["RESTController"];
},
setSchemaController(controller) {
requireMethods(
"SchemaController",
["get", "create", "update", "delete", "send", "purge"],
controller
);
config["SchemaController"] = controller;
},
getSchemaController() {
return config["SchemaController"];
},
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", "getAllKeysAsync"],
controller
);
} else {
requireMethods(
"A synchronous StorageController",
["getItem", "setItem", "removeItem", "getAllKeys"],
controller
);
}
config["StorageController"] = controller;
},
setLocalDatastoreController(controller) {
requireMethods(
"LocalDatastoreController",
["pinWithName", "fromPinWithName", "unPinWithName", "getAllContents", "clear"],
controller
);
config["LocalDatastoreController"] = controller;
},
getLocalDatastoreController() {
return config["LocalDatastoreController"];
},
setLocalDatastore(store) {
config["LocalDatastore"] = store;
},
getLocalDatastore() {
return config["LocalDatastore"];
},
getStorageController() {
return config["StorageController"];
},
setAsyncStorage(storage) {
config["AsyncStorage"] = storage;
},
getAsyncStorage() {
return config["AsyncStorage"];
},
setWebSocketController(controller) {
config["WebSocketController"] = controller;
},
getWebSocketController() {
return config["WebSocketController"];
},
setUserController(controller) {
requireMethods(
"UserController",
[
"setCurrentUser",
"currentUser",
"currentUserAsync",
"signUp",
"logIn",
"become",
"logOut",
"me",
"requestPasswordReset",
"upgradeToRevocableSession",
"requestEmailVerification",
"verifyPassword",
"linkWith"
],
controller
);
config["UserController"] = controller;
},
getUserController() {
return config["UserController"];
},
setLiveQueryController(controller) {
requireMethods(
"LiveQueryController",
["setDefaultLiveQueryClient", "getDefaultLiveQueryClient", "_clearCachedDefaultClient"],
controller
);
config["LiveQueryController"] = controller;
},
getLiveQueryController() {
return config["LiveQueryController"];
},
setHooksController(controller) {
requireMethods("HooksController", ["create", "get", "update", "remove"], controller);
config["HooksController"] = controller;
},
getHooksController() {
return config["HooksController"];
},
setParseOp(op) {
config["ParseOp"] = op;
},
getParseOp() {
return config["ParseOp"];
},
setParseObject(object) {
config["ParseObject"] = object;
},
getParseObject() {
return config["ParseObject"];
},
setParseQuery(query) {
config["ParseQuery"] = query;
},
getParseQuery() {
return config["ParseQuery"];
},
setParseRole(role) {
config["ParseRole"] = role;
},
getParseRole() {
return config["ParseRole"];
},
setParseUser(user) {
config["ParseUser"] = user;
},
getParseUser() {
return config["ParseUser"];
}
};
const _ParseError = class _ParseError extends Error {
/**
* @param {number} code An error code constant from <code>Parse.Error</code>.
* @param {string} message A detailed description of the error.
*/
constructor(code2, message) {
super(message);
this.code = code2;
let customMessage = message;
CoreManager.get("PARSE_ERRORS").forEach((error) => {
if (error.code === code2 && error.code) {
customMessage = error.message;
}
});
Object.defineProperty(this, "message", {
enumerable: true,
value: customMessage
});
}
toString() {
return "ParseError: " + this.code + " " + this.message;
}
};
_ParseError.OTHER_CAUSE = -1;
_ParseError.INTERNAL_SERVER_ERROR = 1;
_ParseError.CONNECTION_FAILED = 100;
_ParseError.OBJECT_NOT_FOUND = 101;
_ParseError.INVALID_QUERY = 102;
_ParseError.INVALID_CLASS_NAME = 103;
_ParseError.MISSING_OBJECT_ID = 104;
_ParseError.INVALID_KEY_NAME = 105;
_ParseError.INVALID_POINTER = 106;
_ParseError.INVALID_JSON = 107;
_ParseError.COMMAND_UNAVAILABLE = 108;
_ParseError.NOT_INITIALIZED = 109;
_ParseError.INCORRECT_TYPE = 111;
_ParseError.INVALID_CHANNEL_NAME = 112;
_ParseError.PUSH_MISCONFIGURED = 115;
_ParseError.OBJECT_TOO_LARGE = 116;
_ParseError.OPERATION_FORBIDDEN = 119;
_ParseError.CACHE_MISS = 120;
_ParseError.INVALID_NESTED_KEY = 121;
_ParseError.INVALID_FILE_NAME = 122;
_ParseError.INVALID_ACL = 123;
_ParseError.TIMEOUT = 124;
_ParseError.INVALID_EMAIL_ADDRESS = 125;
_ParseError.MISSING_CONTENT_TYPE = 126;
_ParseError.MISSING_CONTENT_LENGTH = 127;
_ParseError.INVALID_CONTENT_LENGTH = 128;
_ParseError.FILE_TOO_LARGE = 129;
_ParseError.FILE_SAVE_ERROR = 130;
_ParseError.DUPLICATE_VALUE = 137;
_ParseError.INVALID_ROLE_NAME = 139;
_ParseError.EXCEEDED_QUOTA = 140;
_ParseError.SCRIPT_FAILED = 141;
_ParseError.VALIDATION_ERROR = 142;
_ParseError.INVALID_IMAGE_DATA = 143;
_ParseError.UNSAVED_FILE_ERROR = 151;
_ParseError.INVALID_PUSH_TIME_ERROR = 152;
_ParseError.FILE_DELETE_ERROR = 153;
_ParseError.FILE_DELETE_UNNAMED_ERROR = 161;
_ParseError.REQUEST_LIMIT_EXCEEDED = 155;
_ParseError.DUPLICATE_REQUEST = 159;
_ParseError.INVALID_EVENT_NAME = 160;
_ParseError.INVALID_VALUE = 162;
_ParseError.USERNAME_MISSING = 200;
_ParseError.PASSWORD_MISSING = 201;
_ParseError.USERNAME_TAKEN = 202;
_ParseError.EMAIL_TAKEN = 203;
_ParseError.EMAIL_MISSING = 204;
_ParseError.EMAIL_NOT_FOUND = 205;
_ParseError.SESSION_MISSING = 206;
_ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207;
_ParseError.ACCOUNT_ALREADY_LINKED = 208;
_ParseError.INVALID_SESSION_TOKEN = 209;
_ParseError.MFA_ERROR = 210;
_ParseError.MFA_TOKEN_REQUIRED = 211;
_ParseError.LINKED_ID_MISSING = 250;
_ParseError.INVALID_LINKED_SESSION = 251;
_ParseError.UNSUPPORTED_SERVICE = 252;
_ParseError.INVALID_SCHEMA_OPERATION = 255;
_ParseError.AGGREGATE_ERROR = 600;
_ParseError.FILE_READ_ERROR = 601;
_ParseError.X_DOMAIN_REQUEST = 602;
let ParseError = _ParseError;
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.");
}
class ParseFile {
/**
* @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 Uint8Array.
* 2. an Object like { base64: "..." } with a base64-encoded String.
* 3. an Object like { uri: "..." } with a uri String.
* 4. 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:
* <pre>
* 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.
* });
* }</pre>
* @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.
* @param metadata {object} Optional key value pairs to be stored with file object
* @param tags {object} Optional key value pairs to be stored with file object
*/
constructor(name, data, type2, metadata, tags) {
const specifiedType = type2 || "";
this._name = name;
this._metadata = metadata || {};
this._tags = tags || {};
if (data !== void 0) {
if (Array.isArray(data) || data instanceof Uint8Array) {
this._data = ParseFile.encodeBase64(data);
this._source = {
format: "base64",
base64: this._data,
type: specifiedType
};
} else if (typeof Blob !== "undefined" && data instanceof Blob) {
this._source = {
format: "file",
file: data,
type: specifiedType
};
} else if (data && typeof data.uri === "string" && data.uri !== void 0) {
this._source = {
format: "uri",
uri: data.uri,
type: specifiedType
};
} else if (data && typeof data.base64 === "string") {
const base64 = data.base64.split(",").slice(-1)[0];
const dataType = specifiedType || data.base64.split(";").slice(0, 1)[0].split(":").slice(1, 2)[0] || "text/plain";
this._data = base64;
this._source = {
format: "base64",
base64,
type: dataType
};
} else {
throw new TypeError("Cannot create a Parse.File with that data.");
}
}
}
/**
* Return the data for the file, downloading it if not already present.
* Data is present if initialized with Byte Array, Base64 or Saved with Uri.
* Data is cleared if saved with File object selected with a file upload control
*
* @param {object} options
* @param {function} [options.progress] callback for download progress
* <pre>
* const parseFile = new Parse.File(name, file);
* parseFile.getData({
* progress: (progressValue, loaded, total) => {
* if (progressValue !== null) {
* // Update the UI using progressValue
* }
* }
* });
* </pre>
* @returns {Promise} Promise that is resolve with base64 data
*/
async getData(options) {
options = options || {};
if (this._data) {
return this._data;
}
if (!this._url) {
throw new Error("Cannot retrieve data for unsaved ParseFile.");
}
options.requestTask = (task) => this._requestTask = task;
const controller = CoreManager.getFileController();
const result = await controller.download(this._url, options);
this._data = result.base64;
return this._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.
*
* @returns {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.
*
* @param {object} options An object to specify url options
* @param {boolean} [options.forceSecure] force the url to be secure
* @returns {string | undefined}
*/
url(options) {
options = options || {};
if (!this._url) {
return;
}
if (options.forceSecure) {
return this._url.replace(/^http:\/\//i, "https://");
} else {
return this._url;
}
}
/**
* Gets the metadata of the file.
*
* @returns {object}
*/
metadata() {
return this._metadata;
}
/**
* Gets the tags of the file.
*
* @returns {object}
*/
tags() {
return this._tags;
}
/**
* Saves the file to the Parse cloud.
*
* @param {object} options
* Valid options are:<ul>
* <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
* be used for this request.
* <li>sessionToken: A valid session token, used for making a request on
* behalf of a specific user.
* <li>progress: callback for upload progress. For example:
* <pre>
* let parseFile = new Parse.File(name, file);
* parseFile.save({
* progress: (progressValue, loaded, total) => {
* if (progressValue !== null) {
* // Update the UI using progressValue
* }
* }
* });
* </pre>
* </ul>
* @returns {Promise | undefined} Promise that is resolved when the save finishes.
*/
save(options) {
options = options || {};
options.requestTask = (task) => this._requestTask = task;
options.metadata = this._metadata;
options.tags = this._tags;
const controller = CoreManager.getFileController();
if (!this._previousSave) {
if (this._source.format === "file") {
this._previousSave = controller.saveFile(this._name, this._source, options).then((res) => {
this._name = res.name;
this._url = res.url;
this._data = null;
this._requestTask = null;
return this;
});
} else if (this._source.format === "uri") {
this._previousSave = controller.download(this._source.uri, options).then((result) => {
if (!(result && result.base64)) {
return {};
}
const newSource = {
format: "base64",
base64: result.base64,
type: result.contentType
};
this._data = result.base64;
this._requestTask = null;
return controller.saveBase64(this._name, newSource, options);
}).then((res) => {
this._name = res.name;
this._url = res.url;
this._requestTask = null;
return this;
});
} else {
this._previousSave = controller.saveBase64(this._name, this._source, options).then((res) => {
this._name = res.name;
this._url = res.url;
this._requestTask = null;
return this;
});
}
}
if (this._previousSave) {
return this._previousSave;
}
}
/**
* Aborts the request if it has already been sent.
*/
cancel() {
if (this._requestTask && typeof this._requestTask.abort === "function") {
this._requestTask._aborted = true;
this._requestTask.abort();
}
this._requestTask = null;
}
/**
* Deletes the file from the Parse cloud.
* In Cloud Code and Node only with Master Key.
*
* @param {object} options
* Valid options are:<ul>
* <li>useMasterKey: In Cloud Code and Node only, causes the Master Key to
* be used for this request.
* <pre>
* @returns {Promise} Promise that is resolved when the delete finishes.
*/
destroy(options = {}) {
if (!this._name) {
throw new ParseError(ParseError.FILE_DELETE_UNNAMED_ERROR, "Cannot delete an unnamed file.");
}
const destroyOptions = { useMasterKey: true };
if (Object.hasOwn(options, "useMasterKey")) {
destroyOptions.useMasterKey = !!options.useMasterKey;
}
const controller = CoreManager.getFileController();
return controller.deleteFile(this._name, destroyOptions).then(() => {
this._data = void 0;
this._requestTask = null;
return this;
});
}
toJSON() {
return {
__type: "File",
name: this._name,
url: this._url
};
}
equals(other) {
if (this === other) {
return true;
}
return other instanceof ParseFile && this.name() === other.name() && this.url() === other.url() && typeof this.url() !== "undefined";
}
/**
* Sets metadata to be saved with file object. Overwrites existing metadata
*
* @param {object} metadata Key value pairs to be stored with file object
*/
setMetadata(metadata) {
if (metadata && typeof metadata === "object") {
Object.keys(metadata).forEach((key2) => {
this.addMetadata(key2, metadata[key2]);
});
}
}
/**
* Sets metadata to be saved with file object. Adds to existing metadata.
*
* @param {string} key key to store the metadata
* @param {*} value metadata
*/
addMetadata(key2, value) {
if (typeof key2 === "string") {
this._metadata[key2] = value;
}
}
/**
* Sets tags to be saved with file object. Overwrites existing tags
*
* @param {object} tags Key value pairs to be stored with file object
*/
setTags(tags) {
if (tags && typeof tags === "object") {
Object.keys(tags).forEach((key2) => {
this.addTag(key2, tags[key2]);
});
}
}
/**
* Sets tags to be saved with file object. Adds to existing tags.
*
* @param {string} key key to store tags
* @param {*} value tag
*/
addTag(key2, value) {
if (typeof key2 === "string") {
this._tags[key2] = value;
}
}
static fromJSON(obj) {
if (obj.__type !== "File") {
throw new TypeError("JSON object does not represent a ParseFile");
}
const file = new ParseFile(obj.name);
file._url = obj.url;
return file;
}
static encodeBase64(bytes) {
const chunks = [];
chunks.length = Math.ceil(bytes.length / 3);
for (let i2 = 0; i2 < chunks.length; i2++) {
const b1 = bytes[i2 * 3];
const b2 = bytes[i2 * 3 + 1] || 0;
const b3 = bytes[i2 * 3 + 2] || 0;
const has2 = i2 * 3 + 1 < bytes.length;
const has3 = i2 * 3 + 2 < bytes.length;
chunks[i2] = [
b64Digit(b1 >> 2 & 63),
b64Digit(b1 << 4 & 48 | b2 >> 4 & 15),
has2 ? b64Digit(b2 << 2 & 60 | b3 >> 6 & 3) : "=",
has3 ? b64Digit(b3 & 63) : "="
].join("");
}
return chunks.join("");
}
}
const DefaultController$a = {
saveFile: async function(name, source, options) {
if (source.format !== "file") {
throw new Error("saveFile can only be used with File-type sources.");
}
const base64Data = await new Promise((res, rej) => {
const reader = new FileReader();
reader.onload = () => res(reader.result);
reader.onerror = (error) => rej(error);
reader.readAsDataURL(source.file);
});
const [first, second] = base64Data.split(",");
const data = second ? second : first;
const newSource = {
format: "base64",
base64: data,
type: source.type || (source.file ? source.file.type : void 0)
};
return await DefaultController$a.saveBase64(name, newSource, options);
},
saveBase64: function(name, source, options = {}) {
if (source.format !== "base64") {
throw new Error("saveBase64 can only be used with Base64-type sources.");
}
const data = {
base64: source.base64,
fileData: {
metadata: { ...options.metadata },
tags: { ...options.tags }
}
};
delete options.metadata;
delete options.tags;
if (source.type) {
data._ContentType = source.type;
}
const path = "files/" + name;
return CoreManager.getRESTController().request("POST", path, data, options);
},
download: async function(uri2, options) {
const controller = new AbortController();
options.requestTask(controller);
const { signal } = controller;
try {
const response = await fetch(uri2, { signal });
const reader = response.body.getReader();
const length = +response.headers.get("Content-Length") || 0;
const contentType = response.headers.get("Content-Type");
if (length === 0) {
options.progress?.(null, null, null);
return {
base64: "",
contentType
};
}
let recieved = 0;
const chunks = [];
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
chunks.push(value);
recieved += value?.length || 0;
options.progress?.(recieved / length, recieved, length);
}
const body = new Uint8Array(recieved);
let offset = 0;
for (const chunk of chunks) {
body.set(chunk, offset);
offset += chunk.length;
}
return {
base64: ParseFile.encodeBase64(body),
contentType
};
} catch (error) {
if (error.name === "AbortError") {
return {};
} else {
throw error;
}
}
},
deleteFile: function(name, options) {
const headers = {
"X-Parse-Application-ID": CoreManager.get("APPLICATION_ID")
};
if (options.useMasterKey) {
headers["X-Parse-Master-Key"] = CoreManager.get("MASTER_KEY");
}
let url = CoreManager.get("SERVER_URL");
if (url[url.length - 1] !== "/") {
url += "/";
}
url += "files/" + name;
return CoreManager.getRESTController().ajax("DELETE", url, "", headers).catch((response) => {
if (!response || response.toString() === "SyntaxError: Unexpected end of JSON input") {
return Promise.resolve();
} else {
return CoreManager.getRESTController().handleError(response);
}
});
}
};
CoreManager.setFileController(DefaultController$a);
class ParseGeoPoint {
/**
* @param {(number[] | object | number)} arg1 Either a list of coordinate pairs, an object with `latitude`, `longitude`, or the latitude or the point.
* @param {number} arg2 The longitude of the GeoPoint
*/
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 (arg1 !== void 0 && arg2 !== void 0) {
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 {number} latitude
* @returns {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 {number} longitude
* @returns {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.
*
* @returns {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.
*
* @param {Parse.GeoPoint} point the other Parse.GeoPoint.
* @returns {number}
*/
radiansTo(point) {
const d2r = Math.PI / 180;
const lat1rad = this.latitude * d2r;
const long1rad = this.longitude * d2r;
const lat2rad = point.latitude * d2r;
const long2rad = point.longitude * d2r;
const deltaLat = lat1rad - lat2rad;
const deltaLong = long1rad - long2rad;
const sinDeltaLatDiv2 = Math.sin(deltaLat / 2);
const sinDeltaLongDiv2 = Math.sin(deltaLong / 2);
let a = sinDeltaLatDiv2 * sinDeltaLatDiv2 + Math.cos(lat1rad) * Math.cos(lat2rad) * sinDeltaLongDiv2 * sinDeltaLongDiv2;
a = Math.min(1, a);
return 2 * Math.asin(Math.sqrt(a));
}
/**
* Returns the distance from this GeoPoint to another in kilometers.
*
* @param {Parse.GeoPoint} point the other Parse.GeoPoint.
* @returns {number}
*/
kilometersTo(point) {
return this.radiansTo(point) * 6371;
}
/**
* Returns the distance from this GeoPoint to another in miles.
*
* @param {Parse.GeoPoint} point the other Parse.GeoPoint.
* @returns {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 (isNaN(latitude) || isNaN(longitude) || typeof latitude !== "number" || typeof longitude !== "number") {
throw new TypeError("GeoPoint latitude and longitude must be valid numbers");
}
if (latitude < -90) {
throw new TypeError("GeoPoint latitude out of bounds: " + latitude + " < -90.0.");
}
if (latitude > 90) {
throw new TypeError("GeoPoint latitude out of bounds: " + latitude + " > 90.0.");
}
if (longitude < -180) {
throw new TypeError("GeoPoint longitude out of bounds: " + longitude + " < -180.0.");
}
if (longitude > 180) {
throw new TypeError("GeoPoint longitude out of bounds: " + longitude + " > 180.0.");
}
}
/**
* Creates a GeoPoint with the user's current location, if available.
*
* @param {object} options The options.
* @param {boolean} [options.enableHighAccuracy] A boolean value that indicates the application would like to receive the best possible results.
* If true and if the device is able to provide a more accurate position, it will do so.
* Note that this can result in slower response times or increased power consumption (with a GPS chip on a mobile device for example).
* On the other hand, if false, the device can take the liberty to save resources by responding more quickly and/or using less power. Default: false.
* @param {number} [options.timeout] A positive long value representing the maximum length of time (in milliseconds) the device is allowed to take in order to return a position.
* The default value is Infinity, meaning that getCurrentPosition() won't return until the position is available.
* @param {number} [options.maximumAge] A positive long value indicating the maximum age in milliseconds of a possible cached position that is acceptable to return.
* If set to 0, it means that the device cannot use a cached position and must attempt to retrieve the real current position.
* If set to Infinity the device must return a cached position regardless of its age. Default: 0.
* @static
* @returns {Promise<Parse.GeoPoint>} User's current location
*/
static current(options) {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(location) => {
resolve(new ParseGeoPoint(location.coords.latitude, location.coords.longitude));
},
reject,
options
);
});
}
}
class ParsePolygon {
/**
* @param {(Coordinates | Parse.GeoPoint[])} coordinates An Array of coordinate pairs
*/
constructor(coordinates) {
this._coordinates = ParsePolygon._validate(coordinates);
}
/**
* Coordinates value for this Polygon.
* Throws an exception if not valid type.
*
* @property {(Coordinates | Parse.GeoPoint[])} coordinates list of coordinates
* @returns {Coordinates}
*/
get coordinates() {
return this._coordinates;
}
set coordinates(coords) {
this._coordinates = ParsePolygon._validate(coords);
}
/**
* Returns a JSON representation of the Polygon, suitable for Parse.
*
* @returns {object}
*/
toJSON() {
ParsePolygon._validate(this._coordinates);
return {
__type: "Polygon",
coordinates: this._coordinates
};
}
/**
* Checks if two polygons are equal
*
* @param {(Parse.Polygon | object)} other
* @returns {boolean}
*/
equals(other) {
if (!(other instanceof ParsePolygon) || this.coordinates.length !== other.coordinates.length) {
return false;
}
let isEqual = true;
for (let i2 = 1; i2 < this._coordinates.length; i2 += 1) {
if (this._coordinates[i2][0] != other.coordinates[i2][0] || this._coordinates[i2][1] != other.coordinates[i2][1]) {
isEqual = false;
break;
}
}
return isEqual;
}
/**
*
* @param {Parse.GeoPoint} point
* @returns {boolean} Returns if the point is contained in the polygon
*/
containsPoint(point) {
let minX = this._coordinates[0][0];
let maxX = this._coordinates[0][0];
let minY = this._coordinates[0][1];
let maxY = this._coordinates[0][1];
for (let i2 = 1; i2 < this._coordinates.length; i2 += 1) {
const p = this._coordinates[i2];
minX = Math.min(p[0], minX);
maxX = Math.max(p[0], maxX);
minY = Math.min(p[1], minY);
maxY = Math.max(p[1], maxY);
}
const outside = point.latitude < minX || point.latitude > maxX || point.longitude < minY || point.longitude > maxY;
if (outside) {
return false;
}
let inside = false;
for (let i2 = 0, j = this._coordinates.length - 1; i2 < this._coordinates.length; j = i2++) {
const startX = this._coordinates[i2][0];
const startY = this._coordinates[i2][1];
const endX = this._coordinates[j][0];
const endY = this._coordinates[j][1];
const intersect = startY > point.longitude != endY > point.longitude && point.latitude < (endX - startX) * (point.longitude - startY) / (endY - startY) + startX;
if (intersect) {
inside = !inside;
}
}
return inside;
}
/**
* Validates that the list of coordinates can form a valid polygon
*
* @param {Array} coords the list of coordinates to validate as a polygon
* @throws {TypeError}
* @returns {number[][]} Array of coordinates if validated.
*/
static _validate(coords) {
if (!Array.isArray(coords)) {
throw new TypeError("Coordinates must be an Array");
}
if (coords.length < 3) {
throw new TypeError("Polygon must have at least 3 GeoPoints or Points");
}
const points = [];
for (let i2 = 0; i2 < coords.length; i2 += 1) {
const coord = coords[i2];
let geoPoint;
if (coord instanceof ParseGeoPoint) {
geoPoint = coord;
} else if (Array.isArray(coord) && coord.length === 2) {
geoPoint = new ParseGeoPoint(coord[0], coord[1]);
} else {
throw new TypeError("Coordinates must be an Array of GeoPoints or Points");
}
points.push([geoPoint.latitude, geoPoint.longitude]);
}
return points;
}
}
class ParseRelation {
/**
* @param {Parse.Object} parent The parent of this relation.
* @param {string} key The key for this relation on the parent.
*/
constructor(parent, key2) {
this.parent = parent;
this.key = key2;
this.targetClassName = null;
}
/*
* Makes sure that this relation has the right parent and key.
*/
_ensureParentAndKey(parent, key2) {
this.key = this.key || key2;
if (this.key !== key2) {
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.
*
* @param {(Parse.Object|Array)} objects The item or items to add.
* @returns {Parse.Object} The parent of the relation.
*/
add(objects) {
if (!Array.isArray(objects)) {
objects = [objects];
}
const { RelationOp: RelationOp2 } = CoreManager.getParseOp();
const change = new RelationOp2(objects, []);
const parent = this.parent;
if (!parent) {
throw new Error("Cannot add to a Relation without a parent");
}
if (objects.length === 0) {
return 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.
*
* @param {(Parse.Object|Array)} objects The item or items to remove.
*/
remove(objects) {
if (!Array.isArray(objects)) {
objects = [objects];
}
const { RelationOp: RelationOp2 } = CoreManager.getParseOp();
const change = new RelationOp2([], objects);
if (!this.parent) {
throw new Error("Cannot remove from a Relation without a parent");
}
if (objects.length === 0) {
return;
}
this.parent.set(this.key, change);
this.targetClassName = change._targetClassName;
}
/**
* Returns a JSON version of the object suitable for saving to disk.
*
* @returns {object} JSON representation of Relation
*/
toJSON() {
return {
__type: "Relation",
className: this.targetClassName
};
}
/**
* Returns a Parse.Query that is limited to objects in this
* relation.
*
* @returns {Parse.Query} Relation Query
*/
query() {
let query;
const parent = this.parent;
if (!parent) {
throw new Error("Cannot construct a query for a Relation without a parent");
}
const ParseQuery2 = CoreManager.getParseQuery();
if (!this.targetClassName) {
query = new ParseQuery2(parent.className);
query._extraOptions.redirectClassNameForKey = this.key;
} else {
query = new ParseQuery2(this.targetClassName);
}
query._addCondition("$relatedTo", "object", {
__type: "Pointer",
className: parent.className,
objectId: parent.id
});
query._addCondition("$relatedTo", "key", this.key);
return query;
}
}
function isDangerousKey(key2) {
const dangerousKeys = ["__proto__", "constructor", "prototype"];
if (dangerousKeys.includes(key2)) {
return true;
}
if (key2.includes(".")) {
const parts = key2.split(".");
return parts.some((part) => dangerousKeys.includes(part));
}
return false;
}
function decode(value) {
if (value === null || typeof value !== "object" || value instanceof Date) {
return value;
}
if (Array.isArray(value)) {
const dup = [];
value.forEach((v, i2) => {
dup[i2] = decode(v);
});
return dup;
}
if (typeof value.__op === "string") {
const { opFromJSON: opFromJSON2 } = CoreManager.getParseOp();
return opFromJSON2(value);
}
const ParseObject2 = CoreManager.getParseObject();
if (value.__type === "Pointer" && value.className) {
return ParseObject2.fromJSON(value);
}
if (value.__type === "Object" && value.className) {
return ParseObject2.fromJSON(value);
}
if (value.__type === "Relation") {
const 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
});
}
if (value.__type === "Polygon") {
return new ParsePolygon(value.coordinates);
}
const copy = {};
for (const k in value) {
if (Object.prototype.hasOwnProperty.call(value, k)) {
if (isDangerousKey(k)) {
continue;
}
copy[k] = decode(value[k]);
}
}
return copy;
}
const PUBLIC_KEY$1 = "*";
class ParseACL {
/**
* @param {(Parse.User | object | null)} arg1 The user to initialize the ACL for
*/
constructor(arg1) {
this.permissionsById = {};
if (arg1 && typeof arg1 === "object") {
const ParseUser2 = CoreManager.getParseUser();
if (arg1 instanceof ParseUser2) {
this.setReadAccess(arg1, true);
this.setWriteAccess(arg1, true);
} else {
for (const userId in arg1) {
const accessList = arg1[userId];
this.permissionsById[userId] = {};
for (const permission in accessList) {
const 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.
*
* @returns {object}
*/
toJSON() {
const permissions = {};
for (const p in this.permissionsById) {
permissions[p] = this.permissionsById[p];
}
return permissions;
}
/**
* Returns whether this ACL is equal to another object
*
* @param {ParseACL} other The other object's ACL to compare to
* @returns {boolean}
*/
equals(other) {
if (!(