From c33579c61ceb064df9cafba09ca243c6aa72cfa7 Mon Sep 17 00:00:00 2001 From: swittk Date: Mon, 23 Jan 2023 23:05:34 +0700 Subject: [PATCH 01/27] Fixes pinning of objects that are not ParseObjects into LocalDataStore Fixes https://github.com/parse-community/Parse-SDK-JS/issues/1660 (Caused by passing a Parse.File into the LocalDataStore, which is unexpected) --- src/ParseObject.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ParseObject.js b/src/ParseObject.js index 6e838b72a..112d1c3fe 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.js @@ -2492,8 +2492,10 @@ const DefaultController = { return Promise.reject(objectError); } for (const object of target) { - await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); - await localDatastore._updateObjectIfPinned(object); + if(object instanceof ParseObject) { + await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); + await localDatastore._updateObjectIfPinned(object); + } } return Promise.resolve(target); }); From f02589cba92cf413a5a351db02e41ce1b5caa9e4 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Tue, 24 Jan 2023 06:33:55 +0700 Subject: [PATCH 02/27] added failing test for nested Parse.File (need to shim a more realistic localDataStore) --- src/ParseObject.js | 1 + src/__tests__/ParseFile-test.js | 29 ++++++++++++++++++++++++++++- src/__tests__/ParseObject-test.js | 14 +++++++++++--- 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/ParseObject.js b/src/ParseObject.js index 112d1c3fe..c67331ad4 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.js @@ -2492,6 +2492,7 @@ const DefaultController = { return Promise.reject(objectError); } for (const object of target) { + // Make sure that it is a ParseObject before updating it into the localDataStore if(object instanceof ParseObject) { await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); await localDatastore._updateObjectIfPinned(object); diff --git a/src/__tests__/ParseFile-test.js b/src/__tests__/ParseFile-test.js index 2e66ba19c..53721071b 100644 --- a/src/__tests__/ParseFile-test.js +++ b/src/__tests__/ParseFile-test.js @@ -24,8 +24,17 @@ const mockHttp = require('http'); const mockHttps = require('https'); const mockLocalDatastore = { - _updateLocalIdForObject: jest.fn(), + _updateLocalIdForObject: (localId, /** @type {ParseObject}*/ object) => { + // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject + const objectKey = mockLocalDatastore.getKeyForObject(object); + }, _updateObjectIfPinned: jest.fn(), + getKeyForObject: (object) => { + // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject + const OBJECT_PREFIX = 'Parse_LDS_'; + const objectId = object.objectId || object._getId(); + return `${OBJECT_PREFIX}${object.className}_${objectId}`; + }, }; jest.setMock('../LocalDatastore', mockLocalDatastore); @@ -45,6 +54,8 @@ const defaultController = CoreManager.getFileController(); describe('ParseFile', () => { beforeEach(() => { + ParseObject.enableSingleInstance(); + jest.clearAllMocks(); CoreManager.setFileController({ saveFile: generateSaveMock('http://files.parsetfss.com/a/'), saveBase64: generateSaveMock('http://files.parsetfss.com/a/'), @@ -953,4 +964,20 @@ describe('FileController', () => { } global.FileReader = fileReader; }); + + it('can save unsaved Parse.File property when localDataStore is enabled.', async () => { + mockLocalDatastore.isEnabled = true; + const obj = new ParseObject('Item'); + const aFile = new ParseFile('myFileName', [0, 0, 0, 0, 2, 3, 4, 5]); + obj.set('myName', 'helloworld'); + obj.set('myFile', aFile); + let error = undefined; + try { + await obj.save(); + } catch (e) { + error = e; + } + expect(error).toBeUndefined(); + expect(obj.get('myFile').name()).toBe('myFileName'); + }); }); diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index 0e35f56be..7966d0d6b 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -124,10 +124,18 @@ const mockLocalDatastore = { _serializeObjectsFromPinName: jest.fn(), _serializeObject: jest.fn(), _transverseSerializeObject: jest.fn(), - _updateObjectIfPinned: jest.fn(), _destroyObjectIfPinned: jest.fn(), - _updateLocalIdForObject: jest.fn(), - updateFromServer: jest.fn(), + _updateLocalIdForObject: (localId, /** @type {ParseObject}*/ object) => { + // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject + const objectKey = mockLocalDatastore.getKeyForObject(object); + }, + _updateObjectIfPinned: jest.fn(), + getKeyForObject: (object) => { + // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject + const objectId = object.objectId || object._getId(); + const OBJECT_PREFIX = 'Parse_LDS_'; + return `${OBJECT_PREFIX}${object.className}_${objectId}`; + }, updateFromServer: jest.fn(), _clear: jest.fn(), getKeyForObject: jest.fn(), checkIfEnabled: jest.fn(() => { From 94ca52d3e28731f84c62849d9dcbd164e11b9387 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Tue, 24 Jan 2023 23:26:44 +0700 Subject: [PATCH 03/27] eslint unusedvars --- src/__tests__/ParseFile-test.js | 1 + src/__tests__/ParseObject-test.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/__tests__/ParseFile-test.js b/src/__tests__/ParseFile-test.js index 53721071b..d64ef7636 100644 --- a/src/__tests__/ParseFile-test.js +++ b/src/__tests__/ParseFile-test.js @@ -25,6 +25,7 @@ const mockHttps = require('https'); const mockLocalDatastore = { _updateLocalIdForObject: (localId, /** @type {ParseObject}*/ object) => { + /* eslint-disable no-unused-vars */ // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectKey = mockLocalDatastore.getKeyForObject(object); }, diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index 7966d0d6b..5f47324d9 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -126,6 +126,7 @@ const mockLocalDatastore = { _transverseSerializeObject: jest.fn(), _destroyObjectIfPinned: jest.fn(), _updateLocalIdForObject: (localId, /** @type {ParseObject}*/ object) => { + /* eslint-disable no-unused-vars */ // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectKey = mockLocalDatastore.getKeyForObject(object); }, @@ -137,7 +138,6 @@ const mockLocalDatastore = { return `${OBJECT_PREFIX}${object.className}_${objectId}`; }, updateFromServer: jest.fn(), _clear: jest.fn(), - getKeyForObject: jest.fn(), checkIfEnabled: jest.fn(() => { if (!mockLocalDatastore.isEnabled) { console.error('Parse.enableLocalDatastore() must be called first'); From 42d3944678b9d6dd034ec696c95d7a63b71196de Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Wed, 25 Jan 2023 06:28:04 +0700 Subject: [PATCH 04/27] wrap with jest.fn --- src/__tests__/ParseFile-test.js | 8 ++++---- src/__tests__/ParseObject-test.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/__tests__/ParseFile-test.js b/src/__tests__/ParseFile-test.js index d64ef7636..96a4811af 100644 --- a/src/__tests__/ParseFile-test.js +++ b/src/__tests__/ParseFile-test.js @@ -24,18 +24,18 @@ const mockHttp = require('http'); const mockHttps = require('https'); const mockLocalDatastore = { - _updateLocalIdForObject: (localId, /** @type {ParseObject}*/ object) => { + _updateLocalIdForObject: jest.fn((localId, /** @type {ParseObject}*/ object) => { /* eslint-disable no-unused-vars */ // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectKey = mockLocalDatastore.getKeyForObject(object); - }, + }), _updateObjectIfPinned: jest.fn(), - getKeyForObject: (object) => { + getKeyForObject: jest.fn((object) => { // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const OBJECT_PREFIX = 'Parse_LDS_'; const objectId = object.objectId || object._getId(); return `${OBJECT_PREFIX}${object.className}_${objectId}`; - }, + }), }; jest.setMock('../LocalDatastore', mockLocalDatastore); diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index 5f47324d9..a43126d55 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -125,18 +125,18 @@ const mockLocalDatastore = { _serializeObject: jest.fn(), _transverseSerializeObject: jest.fn(), _destroyObjectIfPinned: jest.fn(), - _updateLocalIdForObject: (localId, /** @type {ParseObject}*/ object) => { + _updateLocalIdForObject: jest.fn((localId, /** @type {ParseObject}*/ object) => { /* eslint-disable no-unused-vars */ // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectKey = mockLocalDatastore.getKeyForObject(object); - }, + }), _updateObjectIfPinned: jest.fn(), - getKeyForObject: (object) => { + getKeyForObject: jest.fn((object) => { // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectId = object.objectId || object._getId(); const OBJECT_PREFIX = 'Parse_LDS_'; return `${OBJECT_PREFIX}${object.className}_${objectId}`; - }, updateFromServer: jest.fn(), + }), updateFromServer: jest.fn(), _clear: jest.fn(), checkIfEnabled: jest.fn(() => { if (!mockLocalDatastore.isEnabled) { From 4ea18e6d7acaae55824d7fa47eb280cad26ffa6d Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Sat, 28 Jan 2023 11:17:23 +0700 Subject: [PATCH 05/27] isEnabled checks --- src/__tests__/ParseFile-test.js | 4 ++++ src/__tests__/ParseObject-test.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/__tests__/ParseFile-test.js b/src/__tests__/ParseFile-test.js index 96a4811af..c8eaf1e43 100644 --- a/src/__tests__/ParseFile-test.js +++ b/src/__tests__/ParseFile-test.js @@ -25,6 +25,9 @@ const mockHttps = require('https'); const mockLocalDatastore = { _updateLocalIdForObject: jest.fn((localId, /** @type {ParseObject}*/ object) => { + if (!mockLocalDatastore.isEnabled) { + return; + } /* eslint-disable no-unused-vars */ // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectKey = mockLocalDatastore.getKeyForObject(object); @@ -968,6 +971,7 @@ describe('FileController', () => { it('can save unsaved Parse.File property when localDataStore is enabled.', async () => { mockLocalDatastore.isEnabled = true; + console.log('isenabled?', mockLocalDatastore.isEnabled); const obj = new ParseObject('Item'); const aFile = new ParseFile('myFileName', [0, 0, 0, 0, 2, 3, 4, 5]); obj.set('myName', 'helloworld'); diff --git a/src/__tests__/ParseObject-test.js b/src/__tests__/ParseObject-test.js index a43126d55..861188ee1 100644 --- a/src/__tests__/ParseObject-test.js +++ b/src/__tests__/ParseObject-test.js @@ -126,6 +126,9 @@ const mockLocalDatastore = { _transverseSerializeObject: jest.fn(), _destroyObjectIfPinned: jest.fn(), _updateLocalIdForObject: jest.fn((localId, /** @type {ParseObject}*/ object) => { + if (!mockLocalDatastore.isEnabled) { + return; + } /* eslint-disable no-unused-vars */ // (Taken from LocalDataStore source) This fails for nested objects that are not ParseObject const objectKey = mockLocalDatastore.getKeyForObject(object); From fce7f31f2db8293279ee77a6a2dd08d40e725c2a Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Sat, 28 Jan 2023 12:22:01 +0700 Subject: [PATCH 06/27] removed error message --- src/__tests__/ParseFile-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/__tests__/ParseFile-test.js b/src/__tests__/ParseFile-test.js index c8eaf1e43..bfba8232c 100644 --- a/src/__tests__/ParseFile-test.js +++ b/src/__tests__/ParseFile-test.js @@ -971,7 +971,6 @@ describe('FileController', () => { it('can save unsaved Parse.File property when localDataStore is enabled.', async () => { mockLocalDatastore.isEnabled = true; - console.log('isenabled?', mockLocalDatastore.isEnabled); const obj = new ParseObject('Item'); const aFile = new ParseFile('myFileName', [0, 0, 0, 0, 2, 3, 4, 5]); obj.set('myName', 'helloworld'); From 7003c945e0a6bf5710bbe4514081175b47e84f0c Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Wed, 1 Feb 2023 20:28:10 +0700 Subject: [PATCH 07/27] changed according to suggestions --- integration/test/ParseFileTest.js | 19 +++++++++++++++++++ src/ParseObject.js | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/integration/test/ParseFileTest.js b/integration/test/ParseFileTest.js index d8e68c309..d31b861a4 100644 --- a/integration/test/ParseFileTest.js +++ b/integration/test/ParseFileTest.js @@ -120,4 +120,23 @@ describe('Parse.File', () => { assert.equal(e.code, Parse.Error.FILE_DELETE_ERROR); } }); + + it('can save file to localDatastore', async () => { + Parse.enableLocalDatastore(); + const file = new Parse.File('parse-js-sdk', [61, 170, 236, 120]); + const object = new Parse.Object('TestObject'); + await object.pin(); + + object.set('file', file); + await object.save(); + + const query = new Parse.Query(TestObject); + query.fromLocalDatastore(); + const results = await query.find(); + + const url = results[0].get('file').url(); + assert.equal(results.length, 1); + assert.notEqual(url, undefined); + assert.equal(url, file.url()); + }); }); diff --git a/src/ParseObject.js b/src/ParseObject.js index 976f549ca..2ce00599b 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.js @@ -2500,7 +2500,7 @@ const DefaultController = { } for (const object of target) { // Make sure that it is a ParseObject before updating it into the localDataStore - if(object instanceof ParseObject) { + if (object instanceof ParseObject) { await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); await localDatastore._updateObjectIfPinned(object); } From 352c0ac136c2ddfc98fcf56713d5f1e4a423287b Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Sun, 29 Oct 2023 17:49:05 +0700 Subject: [PATCH 08/27] bunch of ts --- package-lock.json | 606 +++--------------- src/{CoreManager.js => CoreManager.ts} | 160 ++--- src/EventEmitter.js | 20 - src/EventEmitter.ts | 25 + ...bscription.js => LiveQuerySubscription.ts} | 22 +- ...tastoreUtils.js => LocalDatastoreUtils.ts} | 0 ...teMutations.js => ObjectStateMutations.ts} | 10 +- src/{ParseCLP.js => ParseCLP.ts} | 24 +- src/{ParseConfig.js => ParseConfig.ts} | 6 +- src/ParseError.js | 551 ---------------- src/ParseError.ts | 559 ++++++++++++++++ src/{ParseFile.js => ParseFile.ts} | 95 +-- src/{ParseGeoPoint.js => ParseGeoPoint.ts} | 3 +- src/{ParseHooks.js => ParseHooks.ts} | 36 +- src/{ParseObject.js => ParseObject.ts} | 200 +++--- src/{ParseOp.js => ParseOp.ts} | 158 ++--- src/{ParseRelation.js => ParseRelation.ts} | 10 +- src/{ParseRole.js => ParseRole.ts} | 8 +- src/{ParseSchema.js => ParseSchema.ts} | 39 +- src/ParseSession.ts | 2 +- src/{RESTController.js => RESTController.ts} | 30 +- ...er.js => SingleInstanceStateController.ts} | 10 +- src/{Storage.js => Storage.ts} | 10 +- ...rowser.js => StorageController.browser.ts} | 6 +- src/{TaskQueue.js => TaskQueue.ts} | 9 +- ...er.js => UniqueInstanceStateController.ts} | 10 +- ...ntainsObject.js => arrayContainsObject.ts} | 4 - ...{canBeSerialized.js => canBeSerialized.ts} | 0 src/{decode.js => decode.ts} | 3 +- src/{encode.js => encode.ts} | 12 +- src/{equals.js => equals.ts} | 2 +- src/{escape.js => escape.ts} | 0 ...ocableSession.js => isRevocableSession.ts} | 0 src/{parseDate.js => parseDate.ts} | 2 +- src/{promiseUtils.js => promiseUtils.ts} | 32 +- src/{unique.js => unique.ts} | 0 src/{uuid.js => uuid.ts} | 9 +- 37 files changed, 1165 insertions(+), 1508 deletions(-) rename src/{CoreManager.js => CoreManager.ts} (74%) delete mode 100644 src/EventEmitter.js create mode 100644 src/EventEmitter.ts rename src/{LiveQuerySubscription.js => LiveQuerySubscription.ts} (86%) rename src/{LocalDatastoreUtils.js => LocalDatastoreUtils.ts} (100%) rename src/{ObjectStateMutations.js => ObjectStateMutations.ts} (98%) rename src/{ParseCLP.js => ParseCLP.ts} (96%) rename src/{ParseConfig.js => ParseConfig.ts} (98%) delete mode 100644 src/ParseError.js create mode 100644 src/ParseError.ts rename src/{ParseFile.js => ParseFile.ts} (89%) rename src/{ParseGeoPoint.js => ParseGeoPoint.ts} (98%) rename src/{ParseHooks.js => ParseHooks.ts} (73%) rename src/{ParseObject.js => ParseObject.ts} (93%) rename src/{ParseOp.js => ParseOp.ts} (76%) rename src/{ParseRelation.js => ParseRelation.ts} (95%) rename src/{ParseRole.js => ParseRole.ts} (94%) rename src/{ParseSchema.js => ParseSchema.ts} (93%) rename src/{RESTController.js => RESTController.ts} (93%) rename src/{SingleInstanceStateController.js => SingleInstanceStateController.ts} (94%) rename src/{Storage.js => Storage.ts} (93%) rename src/{StorageController.browser.js => StorageController.browser.ts} (83%) rename src/{TaskQueue.js => TaskQueue.ts} (80%) rename src/{UniqueInstanceStateController.js => UniqueInstanceStateController.ts} (93%) rename src/{arrayContainsObject.js => arrayContainsObject.ts} (96%) rename src/{canBeSerialized.js => canBeSerialized.ts} (100%) rename src/{decode.js => decode.ts} (96%) rename src/{encode.js => encode.ts} (91%) rename src/{equals.js => equals.ts} (95%) rename src/{escape.js => escape.ts} (100%) rename src/{isRevocableSession.js => isRevocableSession.ts} (100%) rename src/{parseDate.js => parseDate.ts} (90%) rename src/{promiseUtils.js => promiseUtils.ts} (64%) rename src/{unique.js => unique.ts} (100%) rename src/{uuid.js => uuid.ts} (67%) diff --git a/package-lock.json b/package-lock.json index b247facd8..f3a7379fb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19320,29 +19320,24 @@ }, "node_modules/npm/node_modules/@colors/colors": { "version": "1.5.0", - "dev": true, "inBundle": true, "license": "MIT", - "optional": true, "engines": { "node": ">=0.1.90" } }, "node_modules/npm/node_modules/@gar/promisify": { "version": "1.1.3", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { "version": "5.6.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19392,7 +19387,6 @@ }, "node_modules/npm/node_modules/@npmcli/ci-detect": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19401,7 +19395,6 @@ }, "node_modules/npm/node_modules/@npmcli/config": { "version": "4.2.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19420,7 +19413,6 @@ }, "node_modules/npm/node_modules/@npmcli/disparity-colors": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19432,7 +19424,6 @@ }, "node_modules/npm/node_modules/@npmcli/fs": { "version": "2.1.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19445,7 +19436,6 @@ }, "node_modules/npm/node_modules/@npmcli/git": { "version": "3.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19465,7 +19455,6 @@ }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { "version": "1.0.7", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19481,7 +19470,6 @@ }, "node_modules/npm/node_modules/@npmcli/installed-package-contents/node_modules/npm-bundled": { "version": "1.1.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19490,7 +19478,6 @@ }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { "version": "2.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19505,7 +19492,6 @@ }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { "version": "3.1.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19520,7 +19506,6 @@ }, "node_modules/npm/node_modules/@npmcli/move-file": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19533,13 +19518,11 @@ }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/node-gyp": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19548,7 +19531,6 @@ }, "node_modules/npm/node_modules/@npmcli/package-json": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19560,7 +19542,6 @@ }, "node_modules/npm/node_modules/@npmcli/promise-spawn": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19572,7 +19553,6 @@ }, "node_modules/npm/node_modules/@npmcli/query": { "version": "1.2.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19586,7 +19566,6 @@ }, "node_modules/npm/node_modules/@npmcli/run-script": { "version": "4.2.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19602,7 +19581,6 @@ }, "node_modules/npm/node_modules/@tootallnate/once": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19611,13 +19589,11 @@ }, "node_modules/npm/node_modules/abbrev": { "version": "1.1.1", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/agent-base": { "version": "6.0.2", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19629,7 +19605,6 @@ }, "node_modules/npm/node_modules/agentkeepalive": { "version": "4.2.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19643,7 +19618,6 @@ }, "node_modules/npm/node_modules/aggregate-error": { "version": "3.1.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19656,7 +19630,6 @@ }, "node_modules/npm/node_modules/ansi-regex": { "version": "5.0.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19665,7 +19638,6 @@ }, "node_modules/npm/node_modules/ansi-styles": { "version": "4.3.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19680,19 +19652,16 @@ }, "node_modules/npm/node_modules/aproba": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/archy": { "version": "1.0.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/are-we-there-yet": { "version": "3.0.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19705,19 +19674,16 @@ }, "node_modules/npm/node_modules/asap": { "version": "2.0.6", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/balanced-match": { "version": "1.0.2", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/bin-links": { "version": "3.0.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19734,7 +19700,6 @@ }, "node_modules/npm/node_modules/bin-links/node_modules/npm-normalize-package-bin": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19743,7 +19708,6 @@ }, "node_modules/npm/node_modules/binary-extensions": { "version": "2.2.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19752,7 +19716,6 @@ }, "node_modules/npm/node_modules/brace-expansion": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19761,7 +19724,6 @@ }, "node_modules/npm/node_modules/builtins": { "version": "5.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19770,7 +19732,6 @@ }, "node_modules/npm/node_modules/cacache": { "version": "16.1.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19799,7 +19760,6 @@ }, "node_modules/npm/node_modules/chalk": { "version": "4.1.2", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19815,7 +19775,6 @@ }, "node_modules/npm/node_modules/chownr": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19824,7 +19783,6 @@ }, "node_modules/npm/node_modules/cidr-regex": { "version": "3.1.1", - "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -19836,7 +19794,6 @@ }, "node_modules/npm/node_modules/clean-stack": { "version": "2.2.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19845,7 +19802,6 @@ }, "node_modules/npm/node_modules/cli-columns": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19858,7 +19814,6 @@ }, "node_modules/npm/node_modules/cli-table3": { "version": "0.6.2", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19873,7 +19828,6 @@ }, "node_modules/npm/node_modules/clone": { "version": "1.0.4", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19882,7 +19836,6 @@ }, "node_modules/npm/node_modules/cmd-shim": { "version": "5.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19894,7 +19847,6 @@ }, "node_modules/npm/node_modules/color-convert": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19906,13 +19858,11 @@ }, "node_modules/npm/node_modules/color-name": { "version": "1.1.4", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/color-support": { "version": "1.1.3", - "dev": true, "inBundle": true, "license": "ISC", "bin": { @@ -19921,7 +19871,6 @@ }, "node_modules/npm/node_modules/columnify": { "version": "1.6.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19934,25 +19883,21 @@ }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/concat-map": { "version": "0.0.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/console-control-strings": { "version": "1.1.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/cssesc": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "MIT", "bin": { @@ -19964,7 +19909,6 @@ }, "node_modules/npm/node_modules/debug": { "version": "4.3.4", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19981,13 +19925,11 @@ }, "node_modules/npm/node_modules/debug/node_modules/ms": { "version": "2.1.2", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/debuglog": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19996,7 +19938,6 @@ }, "node_modules/npm/node_modules/defaults": { "version": "1.0.3", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20005,13 +19946,11 @@ }, "node_modules/npm/node_modules/delegates": { "version": "1.0.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/depd": { "version": "1.1.2", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20020,7 +19959,6 @@ }, "node_modules/npm/node_modules/dezalgo": { "version": "1.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20030,7 +19968,6 @@ }, "node_modules/npm/node_modules/diff": { "version": "5.1.0", - "dev": true, "inBundle": true, "license": "BSD-3-Clause", "engines": { @@ -20039,23 +19976,19 @@ }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/encoding": { "version": "0.1.13", - "dev": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "iconv-lite": "^0.6.2" } }, "node_modules/npm/node_modules/env-paths": { "version": "2.2.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20064,19 +19997,16 @@ }, "node_modules/npm/node_modules/err-code": { "version": "2.0.3", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/fastest-levenshtein": { "version": "1.0.12", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/fs-minipass": { "version": "2.1.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20088,19 +20018,16 @@ }, "node_modules/npm/node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/function-bind": { "version": "1.1.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/gauge": { "version": "4.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20119,7 +20046,6 @@ }, "node_modules/npm/node_modules/glob": { "version": "8.0.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20138,13 +20064,11 @@ }, "node_modules/npm/node_modules/graceful-fs": { "version": "4.2.10", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/has": { "version": "1.0.3", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20156,7 +20080,6 @@ }, "node_modules/npm/node_modules/has-flag": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20165,13 +20088,11 @@ }, "node_modules/npm/node_modules/has-unicode": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/hosted-git-info": { "version": "5.1.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20183,13 +20104,11 @@ }, "node_modules/npm/node_modules/http-cache-semantics": { "version": "4.1.0", - "dev": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/http-proxy-agent": { "version": "5.0.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20203,7 +20122,6 @@ }, "node_modules/npm/node_modules/https-proxy-agent": { "version": "5.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20216,7 +20134,6 @@ }, "node_modules/npm/node_modules/humanize-ms": { "version": "1.2.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20225,10 +20142,8 @@ }, "node_modules/npm/node_modules/iconv-lite": { "version": "0.6.3", - "dev": true, "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -20238,7 +20153,6 @@ }, "node_modules/npm/node_modules/ignore-walk": { "version": "5.0.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20250,7 +20164,6 @@ }, "node_modules/npm/node_modules/imurmurhash": { "version": "0.1.4", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20259,7 +20172,6 @@ }, "node_modules/npm/node_modules/indent-string": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20268,13 +20180,11 @@ }, "node_modules/npm/node_modules/infer-owner": { "version": "1.0.4", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/inflight": { "version": "1.0.6", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20284,13 +20194,11 @@ }, "node_modules/npm/node_modules/inherits": { "version": "2.0.4", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/ini": { "version": "3.0.1", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20299,7 +20207,6 @@ }, "node_modules/npm/node_modules/init-package-json": { "version": "3.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20317,13 +20224,11 @@ }, "node_modules/npm/node_modules/ip": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/ip-regex": { "version": "4.3.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20332,7 +20237,6 @@ }, "node_modules/npm/node_modules/is-cidr": { "version": "4.0.2", - "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -20344,7 +20248,6 @@ }, "node_modules/npm/node_modules/is-core-module": { "version": "2.10.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20356,7 +20259,6 @@ }, "node_modules/npm/node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20365,25 +20267,21 @@ }, "node_modules/npm/node_modules/is-lambda": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/isexe": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/json-parse-even-better-errors": { "version": "2.3.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/json-stringify-nice": { "version": "1.1.4", - "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -20392,7 +20290,6 @@ }, "node_modules/npm/node_modules/jsonparse": { "version": "1.3.1", - "dev": true, "engines": [ "node >= 0.2.0" ], @@ -20401,19 +20298,16 @@ }, "node_modules/npm/node_modules/just-diff": { "version": "5.1.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/just-diff-apply": { "version": "5.4.1", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { "version": "6.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20428,7 +20322,6 @@ }, "node_modules/npm/node_modules/libnpmdiff": { "version": "4.0.5", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20447,7 +20340,6 @@ }, "node_modules/npm/node_modules/libnpmexec": { "version": "4.0.12", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20472,7 +20364,6 @@ }, "node_modules/npm/node_modules/libnpmfund": { "version": "3.0.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20484,7 +20375,6 @@ }, "node_modules/npm/node_modules/libnpmhook": { "version": "8.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20497,7 +20387,6 @@ }, "node_modules/npm/node_modules/libnpmorg": { "version": "4.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20510,7 +20399,6 @@ }, "node_modules/npm/node_modules/libnpmpack": { "version": "4.1.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20524,7 +20412,6 @@ }, "node_modules/npm/node_modules/libnpmpublish": { "version": "6.0.5", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20540,7 +20427,6 @@ }, "node_modules/npm/node_modules/libnpmsearch": { "version": "5.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20552,7 +20438,6 @@ }, "node_modules/npm/node_modules/libnpmteam": { "version": "4.0.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20565,7 +20450,6 @@ }, "node_modules/npm/node_modules/libnpmversion": { "version": "3.0.7", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20581,7 +20465,6 @@ }, "node_modules/npm/node_modules/lru-cache": { "version": "7.13.2", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20590,7 +20473,6 @@ }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "10.2.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20617,7 +20499,6 @@ }, "node_modules/npm/node_modules/minimatch": { "version": "5.1.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20629,7 +20510,6 @@ }, "node_modules/npm/node_modules/minipass": { "version": "3.3.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20641,7 +20521,6 @@ }, "node_modules/npm/node_modules/minipass-collect": { "version": "1.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20653,7 +20532,6 @@ }, "node_modules/npm/node_modules/minipass-fetch": { "version": "2.1.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20670,7 +20548,6 @@ }, "node_modules/npm/node_modules/minipass-flush": { "version": "1.0.5", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20682,7 +20559,6 @@ }, "node_modules/npm/node_modules/minipass-json-stream": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20692,7 +20568,6 @@ }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20704,7 +20579,6 @@ }, "node_modules/npm/node_modules/minipass-sized": { "version": "1.0.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20716,7 +20590,6 @@ }, "node_modules/npm/node_modules/minizlib": { "version": "2.1.2", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20729,7 +20602,6 @@ }, "node_modules/npm/node_modules/mkdirp": { "version": "1.0.4", - "dev": true, "inBundle": true, "license": "MIT", "bin": { @@ -20741,7 +20613,6 @@ }, "node_modules/npm/node_modules/mkdirp-infer-owner": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20755,19 +20626,16 @@ }, "node_modules/npm/node_modules/ms": { "version": "2.1.3", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/mute-stream": { "version": "0.0.8", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/negotiator": { "version": "0.6.3", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20776,7 +20644,6 @@ }, "node_modules/npm/node_modules/node-gyp": { "version": "9.1.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20800,7 +20667,6 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20810,7 +20676,6 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/glob": { "version": "7.2.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20830,7 +20695,6 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20842,7 +20706,6 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { "version": "5.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20857,7 +20720,6 @@ }, "node_modules/npm/node_modules/nopt": { "version": "6.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20872,7 +20734,6 @@ }, "node_modules/npm/node_modules/normalize-package-data": { "version": "4.0.1", - "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -20887,7 +20748,6 @@ }, "node_modules/npm/node_modules/npm-audit-report": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20899,7 +20759,6 @@ }, "node_modules/npm/node_modules/npm-bundled": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20911,7 +20770,6 @@ }, "node_modules/npm/node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20920,7 +20778,6 @@ }, "node_modules/npm/node_modules/npm-install-checks": { "version": "5.0.0", - "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -20932,13 +20789,11 @@ }, "node_modules/npm/node_modules/npm-normalize-package-bin": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/npm-package-arg": { "version": "9.1.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20953,7 +20808,6 @@ }, "node_modules/npm/node_modules/npm-packlist": { "version": "5.1.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20971,7 +20825,6 @@ }, "node_modules/npm/node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20980,7 +20833,6 @@ }, "node_modules/npm/node_modules/npm-pick-manifest": { "version": "7.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20995,7 +20847,6 @@ }, "node_modules/npm/node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21004,7 +20855,6 @@ }, "node_modules/npm/node_modules/npm-profile": { "version": "6.2.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21017,7 +20867,6 @@ }, "node_modules/npm/node_modules/npm-registry-fetch": { "version": "13.3.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21035,13 +20884,11 @@ }, "node_modules/npm/node_modules/npm-user-validate": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/npmlog": { "version": "6.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21056,7 +20903,6 @@ }, "node_modules/npm/node_modules/once": { "version": "1.4.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21065,7 +20911,6 @@ }, "node_modules/npm/node_modules/opener": { "version": "1.5.2", - "dev": true, "inBundle": true, "license": "(WTFPL OR MIT)", "bin": { @@ -21074,7 +20919,6 @@ }, "node_modules/npm/node_modules/p-map": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21089,7 +20933,6 @@ }, "node_modules/npm/node_modules/pacote": { "version": "13.6.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21124,7 +20967,6 @@ }, "node_modules/npm/node_modules/parse-conflict-json": { "version": "2.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21138,7 +20980,6 @@ }, "node_modules/npm/node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -21147,7 +20988,6 @@ }, "node_modules/npm/node_modules/postcss-selector-parser": { "version": "6.0.10", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21160,7 +21000,6 @@ }, "node_modules/npm/node_modules/proc-log": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21169,7 +21008,6 @@ }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -21178,7 +21016,6 @@ }, "node_modules/npm/node_modules/promise-call-limit": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -21187,13 +21024,11 @@ }, "node_modules/npm/node_modules/promise-inflight": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21206,7 +21041,6 @@ }, "node_modules/npm/node_modules/promzard": { "version": "0.3.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21215,7 +21049,6 @@ }, "node_modules/npm/node_modules/qrcode-terminal": { "version": "0.12.0", - "dev": true, "inBundle": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" @@ -21223,7 +21056,6 @@ }, "node_modules/npm/node_modules/read": { "version": "1.0.7", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21235,7 +21067,6 @@ }, "node_modules/npm/node_modules/read-cmd-shim": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21244,7 +21075,6 @@ }, "node_modules/npm/node_modules/read-package-json": { "version": "5.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21259,7 +21089,6 @@ }, "node_modules/npm/node_modules/read-package-json-fast": { "version": "2.0.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21272,7 +21101,6 @@ }, "node_modules/npm/node_modules/read-package-json/node_modules/npm-normalize-package-bin": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21281,7 +21109,6 @@ }, "node_modules/npm/node_modules/readable-stream": { "version": "3.6.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21295,7 +21122,6 @@ }, "node_modules/npm/node_modules/readdir-scoped-modules": { "version": "1.1.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21307,7 +21133,6 @@ }, "node_modules/npm/node_modules/retry": { "version": "0.12.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -21316,7 +21141,6 @@ }, "node_modules/npm/node_modules/rimraf": { "version": "3.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21331,7 +21155,6 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21341,7 +21164,6 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/glob": { "version": "7.2.3", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21361,7 +21183,6 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21373,7 +21194,6 @@ }, "node_modules/npm/node_modules/safe-buffer": { "version": "5.2.1", - "dev": true, "funding": [ { "type": "github", @@ -21393,14 +21213,11 @@ }, "node_modules/npm/node_modules/safer-buffer": { "version": "2.1.2", - "dev": true, "inBundle": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/npm/node_modules/semver": { "version": "7.3.7", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21415,7 +21232,6 @@ }, "node_modules/npm/node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21427,19 +21243,16 @@ }, "node_modules/npm/node_modules/set-blocking": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/signal-exit": { "version": "3.0.7", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/smart-buffer": { "version": "4.2.0", - "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -21449,7 +21262,6 @@ }, "node_modules/npm/node_modules/socks": { "version": "2.7.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21463,7 +21275,6 @@ }, "node_modules/npm/node_modules/socks-proxy-agent": { "version": "7.0.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21477,7 +21288,6 @@ }, "node_modules/npm/node_modules/spdx-correct": { "version": "3.1.1", - "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -21487,13 +21297,11 @@ }, "node_modules/npm/node_modules/spdx-exceptions": { "version": "2.3.0", - "dev": true, "inBundle": true, "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { "version": "3.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21503,13 +21311,11 @@ }, "node_modules/npm/node_modules/spdx-license-ids": { "version": "3.0.11", - "dev": true, "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { "version": "9.0.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21521,7 +21327,6 @@ }, "node_modules/npm/node_modules/string_decoder": { "version": "1.3.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21530,7 +21335,6 @@ }, "node_modules/npm/node_modules/string-width": { "version": "4.2.3", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21544,7 +21348,6 @@ }, "node_modules/npm/node_modules/strip-ansi": { "version": "6.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21556,7 +21359,6 @@ }, "node_modules/npm/node_modules/supports-color": { "version": "7.2.0", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21568,7 +21370,6 @@ }, "node_modules/npm/node_modules/tar": { "version": "6.1.11", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21585,19 +21386,16 @@ }, "node_modules/npm/node_modules/text-table": { "version": "0.2.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/tiny-relative-date": { "version": "1.3.0", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/treeverse": { "version": "2.0.0", - "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21606,7 +21404,6 @@ }, "node_modules/npm/node_modules/unique-filename": { "version": "2.0.1", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21618,7 +21415,6 @@ }, "node_modules/npm/node_modules/unique-slug": { "version": "3.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21630,13 +21426,11 @@ }, "node_modules/npm/node_modules/util-deprecate": { "version": "1.0.2", - "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/validate-npm-package-license": { "version": "3.0.4", - "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -21646,7 +21440,6 @@ }, "node_modules/npm/node_modules/validate-npm-package-name": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21658,13 +21451,11 @@ }, "node_modules/npm/node_modules/walk-up-path": { "version": "1.0.0", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/wcwidth": { "version": "1.0.1", - "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21673,7 +21464,6 @@ }, "node_modules/npm/node_modules/which": { "version": "2.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21688,7 +21478,6 @@ }, "node_modules/npm/node_modules/wide-align": { "version": "1.1.5", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21697,13 +21486,11 @@ }, "node_modules/npm/node_modules/wrappy": { "version": "1.0.2", - "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/write-file-atomic": { "version": "4.0.2", - "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21716,7 +21503,6 @@ }, "node_modules/npm/node_modules/yallist": { "version": "4.0.0", - "dev": true, "inBundle": true, "license": "ISC" }, @@ -42734,24 +42520,19 @@ "dependencies": { "@colors/colors": { "version": "1.5.0", - "bundled": true, - "dev": true, - "optional": true + "bundled": true }, "@gar/promisify": { "version": "1.1.3", - "bundled": true, - "dev": true + "bundled": true }, "@isaacs/string-locale-compare": { "version": "1.1.0", - "bundled": true, - "dev": true + "bundled": true }, "@npmcli/arborist": { "version": "5.6.1", "bundled": true, - "dev": true, "requires": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -42793,13 +42574,11 @@ }, "@npmcli/ci-detect": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "@npmcli/config": { "version": "4.2.2", "bundled": true, - "dev": true, "requires": { "@npmcli/map-workspaces": "^2.0.2", "ini": "^3.0.0", @@ -42814,7 +42593,6 @@ "@npmcli/disparity-colors": { "version": "2.0.0", "bundled": true, - "dev": true, "requires": { "ansi-styles": "^4.3.0" } @@ -42822,7 +42600,6 @@ "@npmcli/fs": { "version": "2.1.2", "bundled": true, - "dev": true, "requires": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" @@ -42831,7 +42608,6 @@ "@npmcli/git": { "version": "3.0.2", "bundled": true, - "dev": true, "requires": { "@npmcli/promise-spawn": "^3.0.0", "lru-cache": "^7.4.4", @@ -42847,7 +42623,6 @@ "@npmcli/installed-package-contents": { "version": "1.0.7", "bundled": true, - "dev": true, "requires": { "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" @@ -42856,7 +42631,6 @@ "npm-bundled": { "version": "1.1.2", "bundled": true, - "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -42866,7 +42640,6 @@ "@npmcli/map-workspaces": { "version": "2.0.4", "bundled": true, - "dev": true, "requires": { "@npmcli/name-from-folder": "^1.0.1", "glob": "^8.0.1", @@ -42877,7 +42650,6 @@ "@npmcli/metavuln-calculator": { "version": "3.1.1", "bundled": true, - "dev": true, "requires": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", @@ -42888,7 +42660,6 @@ "@npmcli/move-file": { "version": "2.0.1", "bundled": true, - "dev": true, "requires": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -42896,18 +42667,15 @@ }, "@npmcli/name-from-folder": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "@npmcli/node-gyp": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "@npmcli/package-json": { "version": "2.0.0", "bundled": true, - "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.1" } @@ -42915,7 +42683,6 @@ "@npmcli/promise-spawn": { "version": "3.0.0", "bundled": true, - "dev": true, "requires": { "infer-owner": "^1.0.4" } @@ -42923,7 +42690,6 @@ "@npmcli/query": { "version": "1.2.0", "bundled": true, - "dev": true, "requires": { "npm-package-arg": "^9.1.0", "postcss-selector-parser": "^6.0.10", @@ -42933,7 +42699,6 @@ "@npmcli/run-script": { "version": "4.2.1", "bundled": true, - "dev": true, "requires": { "@npmcli/node-gyp": "^2.0.0", "@npmcli/promise-spawn": "^3.0.0", @@ -42944,18 +42709,15 @@ }, "@tootallnate/once": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "abbrev": { "version": "1.1.1", - "bundled": true, - "dev": true + "bundled": true }, "agent-base": { "version": "6.0.2", "bundled": true, - "dev": true, "requires": { "debug": "4" } @@ -42963,7 +42725,6 @@ "agentkeepalive": { "version": "4.2.1", "bundled": true, - "dev": true, "requires": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -42973,7 +42734,6 @@ "aggregate-error": { "version": "3.1.0", "bundled": true, - "dev": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -42981,31 +42741,26 @@ }, "ansi-regex": { "version": "5.0.1", - "bundled": true, - "dev": true + "bundled": true }, "ansi-styles": { "version": "4.3.0", "bundled": true, - "dev": true, "requires": { "color-convert": "^2.0.1" } }, "aproba": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "archy": { "version": "1.0.0", - "bundled": true, - "dev": true + "bundled": true }, "are-we-there-yet": { "version": "3.0.1", "bundled": true, - "dev": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -43013,18 +42768,15 @@ }, "asap": { "version": "2.0.6", - "bundled": true, - "dev": true + "bundled": true }, "balanced-match": { "version": "1.0.2", - "bundled": true, - "dev": true + "bundled": true }, "bin-links": { "version": "3.0.3", "bundled": true, - "dev": true, "requires": { "cmd-shim": "^5.0.0", "mkdirp-infer-owner": "^2.0.0", @@ -43036,20 +42788,17 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true } } }, "binary-extensions": { "version": "2.2.0", - "bundled": true, - "dev": true + "bundled": true }, "brace-expansion": { "version": "2.0.1", "bundled": true, - "dev": true, "requires": { "balanced-match": "^1.0.0" } @@ -43057,7 +42806,6 @@ "builtins": { "version": "5.0.1", "bundled": true, - "dev": true, "requires": { "semver": "^7.0.0" } @@ -43065,7 +42813,6 @@ "cacache": { "version": "16.1.3", "bundled": true, - "dev": true, "requires": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", @@ -43090,7 +42837,6 @@ "chalk": { "version": "4.1.2", "bundled": true, - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -43098,26 +42844,22 @@ }, "chownr": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "cidr-regex": { "version": "3.1.1", "bundled": true, - "dev": true, "requires": { "ip-regex": "^4.1.0" } }, "clean-stack": { "version": "2.2.0", - "bundled": true, - "dev": true + "bundled": true }, "cli-columns": { "version": "4.0.0", "bundled": true, - "dev": true, "requires": { "string-width": "^4.2.3", "strip-ansi": "^6.0.1" @@ -43126,7 +42868,6 @@ "cli-table3": { "version": "0.6.2", "bundled": true, - "dev": true, "requires": { "@colors/colors": "1.5.0", "string-width": "^4.2.0" @@ -43134,13 +42875,11 @@ }, "clone": { "version": "1.0.4", - "bundled": true, - "dev": true + "bundled": true }, "cmd-shim": { "version": "5.0.0", "bundled": true, - "dev": true, "requires": { "mkdirp-infer-owner": "^2.0.0" } @@ -43148,25 +42887,21 @@ "color-convert": { "version": "2.0.1", "bundled": true, - "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", - "bundled": true, - "dev": true + "bundled": true }, "color-support": { "version": "1.1.3", - "bundled": true, - "dev": true + "bundled": true }, "columnify": { "version": "1.6.0", "bundled": true, - "dev": true, "requires": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" @@ -43174,66 +42909,55 @@ }, "common-ancestor-path": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "concat-map": { "version": "0.0.1", - "bundled": true, - "dev": true + "bundled": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true, - "dev": true + "bundled": true }, "cssesc": { "version": "3.0.0", - "bundled": true, - "dev": true + "bundled": true }, "debug": { "version": "4.3.4", "bundled": true, - "dev": true, "requires": { "ms": "2.1.2" }, "dependencies": { "ms": { "version": "2.1.2", - "bundled": true, - "dev": true + "bundled": true } } }, "debuglog": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "defaults": { "version": "1.0.3", "bundled": true, - "dev": true, "requires": { "clone": "^1.0.2" } }, "delegates": { "version": "1.0.0", - "bundled": true, - "dev": true + "bundled": true }, "depd": { "version": "1.1.2", - "bundled": true, - "dev": true + "bundled": true }, "dezalgo": { "version": "1.0.4", "bundled": true, - "dev": true, "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -43241,60 +42965,49 @@ }, "diff": { "version": "5.1.0", - "bundled": true, - "dev": true + "bundled": true }, "emoji-regex": { "version": "8.0.0", - "bundled": true, - "dev": true + "bundled": true }, "encoding": { "version": "0.1.13", "bundled": true, - "dev": true, - "optional": true, "requires": { "iconv-lite": "^0.6.2" } }, "env-paths": { "version": "2.2.1", - "bundled": true, - "dev": true + "bundled": true }, "err-code": { "version": "2.0.3", - "bundled": true, - "dev": true + "bundled": true }, "fastest-levenshtein": { "version": "1.0.12", - "bundled": true, - "dev": true + "bundled": true }, "fs-minipass": { "version": "2.1.0", "bundled": true, - "dev": true, "requires": { "minipass": "^3.0.0" } }, "fs.realpath": { "version": "1.0.0", - "bundled": true, - "dev": true + "bundled": true }, "function-bind": { "version": "1.1.1", - "bundled": true, - "dev": true + "bundled": true }, "gauge": { "version": "4.0.4", "bundled": true, - "dev": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -43309,7 +43022,6 @@ "glob": { "version": "8.0.3", "bundled": true, - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -43320,44 +43032,37 @@ }, "graceful-fs": { "version": "4.2.10", - "bundled": true, - "dev": true + "bundled": true }, "has": { "version": "1.0.3", "bundled": true, - "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "4.0.0", - "bundled": true, - "dev": true + "bundled": true }, "has-unicode": { "version": "2.0.1", - "bundled": true, - "dev": true + "bundled": true }, "hosted-git-info": { "version": "5.1.0", "bundled": true, - "dev": true, "requires": { "lru-cache": "^7.5.1" } }, "http-cache-semantics": { "version": "4.1.0", - "bundled": true, - "dev": true + "bundled": true }, "http-proxy-agent": { "version": "5.0.0", "bundled": true, - "dev": true, "requires": { "@tootallnate/once": "2", "agent-base": "6", @@ -43367,7 +43072,6 @@ "https-proxy-agent": { "version": "5.0.1", "bundled": true, - "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -43376,7 +43080,6 @@ "humanize-ms": { "version": "1.2.1", "bundled": true, - "dev": true, "requires": { "ms": "^2.0.0" } @@ -43384,8 +43087,6 @@ "iconv-lite": { "version": "0.6.3", "bundled": true, - "dev": true, - "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -43393,30 +43094,25 @@ "ignore-walk": { "version": "5.0.1", "bundled": true, - "dev": true, "requires": { "minimatch": "^5.0.1" } }, "imurmurhash": { "version": "0.1.4", - "bundled": true, - "dev": true + "bundled": true }, "indent-string": { "version": "4.0.0", - "bundled": true, - "dev": true + "bundled": true }, "infer-owner": { "version": "1.0.4", - "bundled": true, - "dev": true + "bundled": true }, "inflight": { "version": "1.0.6", "bundled": true, - "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -43424,18 +43120,15 @@ }, "inherits": { "version": "2.0.4", - "bundled": true, - "dev": true + "bundled": true }, "ini": { "version": "3.0.1", - "bundled": true, - "dev": true + "bundled": true }, "init-package-json": { "version": "3.0.2", "bundled": true, - "dev": true, "requires": { "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", @@ -43448,18 +43141,15 @@ }, "ip": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "ip-regex": { "version": "4.3.0", - "bundled": true, - "dev": true + "bundled": true }, "is-cidr": { "version": "4.0.2", "bundled": true, - "dev": true, "requires": { "cidr-regex": "^3.1.1" } @@ -43467,55 +43157,45 @@ "is-core-module": { "version": "2.10.0", "bundled": true, - "dev": true, "requires": { "has": "^1.0.3" } }, "is-fullwidth-code-point": { "version": "3.0.0", - "bundled": true, - "dev": true + "bundled": true }, "is-lambda": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "isexe": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "json-parse-even-better-errors": { "version": "2.3.1", - "bundled": true, - "dev": true + "bundled": true }, "json-stringify-nice": { "version": "1.1.4", - "bundled": true, - "dev": true + "bundled": true }, "jsonparse": { "version": "1.3.1", - "bundled": true, - "dev": true + "bundled": true }, "just-diff": { "version": "5.1.1", - "bundled": true, - "dev": true + "bundled": true }, "just-diff-apply": { "version": "5.4.1", - "bundled": true, - "dev": true + "bundled": true }, "libnpmaccess": { "version": "6.0.4", "bundled": true, - "dev": true, "requires": { "aproba": "^2.0.0", "minipass": "^3.1.1", @@ -43526,7 +43206,6 @@ "libnpmdiff": { "version": "4.0.5", "bundled": true, - "dev": true, "requires": { "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -43541,7 +43220,6 @@ "libnpmexec": { "version": "4.0.12", "bundled": true, - "dev": true, "requires": { "@npmcli/arborist": "^5.6.1", "@npmcli/ci-detect": "^2.0.0", @@ -43562,7 +43240,6 @@ "libnpmfund": { "version": "3.0.3", "bundled": true, - "dev": true, "requires": { "@npmcli/arborist": "^5.6.1" } @@ -43570,7 +43247,6 @@ "libnpmhook": { "version": "8.0.4", "bundled": true, - "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -43579,7 +43255,6 @@ "libnpmorg": { "version": "4.0.4", "bundled": true, - "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -43588,7 +43263,6 @@ "libnpmpack": { "version": "4.1.3", "bundled": true, - "dev": true, "requires": { "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", @@ -43598,7 +43272,6 @@ "libnpmpublish": { "version": "6.0.5", "bundled": true, - "dev": true, "requires": { "normalize-package-data": "^4.0.0", "npm-package-arg": "^9.0.1", @@ -43610,7 +43283,6 @@ "libnpmsearch": { "version": "5.0.4", "bundled": true, - "dev": true, "requires": { "npm-registry-fetch": "^13.0.0" } @@ -43618,7 +43290,6 @@ "libnpmteam": { "version": "4.0.4", "bundled": true, - "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -43627,7 +43298,6 @@ "libnpmversion": { "version": "3.0.7", "bundled": true, - "dev": true, "requires": { "@npmcli/git": "^3.0.0", "@npmcli/run-script": "^4.1.3", @@ -43638,13 +43308,11 @@ }, "lru-cache": { "version": "7.13.2", - "bundled": true, - "dev": true + "bundled": true }, "make-fetch-happen": { "version": "10.2.1", "bundled": true, - "dev": true, "requires": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -43667,7 +43335,6 @@ "minimatch": { "version": "5.1.0", "bundled": true, - "dev": true, "requires": { "brace-expansion": "^2.0.1" } @@ -43675,7 +43342,6 @@ "minipass": { "version": "3.3.4", "bundled": true, - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -43683,7 +43349,6 @@ "minipass-collect": { "version": "1.0.2", "bundled": true, - "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43691,7 +43356,6 @@ "minipass-fetch": { "version": "2.1.1", "bundled": true, - "dev": true, "requires": { "encoding": "^0.1.13", "minipass": "^3.1.6", @@ -43702,7 +43366,6 @@ "minipass-flush": { "version": "1.0.5", "bundled": true, - "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43710,7 +43373,6 @@ "minipass-json-stream": { "version": "1.0.1", "bundled": true, - "dev": true, "requires": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -43719,7 +43381,6 @@ "minipass-pipeline": { "version": "1.2.4", "bundled": true, - "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43727,7 +43388,6 @@ "minipass-sized": { "version": "1.0.3", "bundled": true, - "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43735,7 +43395,6 @@ "minizlib": { "version": "2.1.2", "bundled": true, - "dev": true, "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -43743,13 +43402,11 @@ }, "mkdirp": { "version": "1.0.4", - "bundled": true, - "dev": true + "bundled": true }, "mkdirp-infer-owner": { "version": "2.0.0", "bundled": true, - "dev": true, "requires": { "chownr": "^2.0.0", "infer-owner": "^1.0.4", @@ -43758,23 +43415,19 @@ }, "ms": { "version": "2.1.3", - "bundled": true, - "dev": true + "bundled": true }, "mute-stream": { "version": "0.0.8", - "bundled": true, - "dev": true + "bundled": true }, "negotiator": { "version": "0.6.3", - "bundled": true, - "dev": true + "bundled": true }, "node-gyp": { "version": "9.1.0", "bundled": true, - "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -43791,7 +43444,6 @@ "brace-expansion": { "version": "1.1.11", "bundled": true, - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -43800,7 +43452,6 @@ "glob": { "version": "7.2.3", "bundled": true, - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -43813,7 +43464,6 @@ "minimatch": { "version": "3.1.2", "bundled": true, - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -43821,7 +43471,6 @@ "nopt": { "version": "5.0.0", "bundled": true, - "dev": true, "requires": { "abbrev": "1" } @@ -43831,7 +43480,6 @@ "nopt": { "version": "6.0.0", "bundled": true, - "dev": true, "requires": { "abbrev": "^1.0.0" } @@ -43839,7 +43487,6 @@ "normalize-package-data": { "version": "4.0.1", "bundled": true, - "dev": true, "requires": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -43850,7 +43497,6 @@ "npm-audit-report": { "version": "3.0.0", "bundled": true, - "dev": true, "requires": { "chalk": "^4.0.0" } @@ -43858,35 +43504,30 @@ "npm-bundled": { "version": "2.0.1", "bundled": true, - "dev": true, "requires": { "npm-normalize-package-bin": "^2.0.0" }, "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true } } }, "npm-install-checks": { "version": "5.0.0", "bundled": true, - "dev": true, "requires": { "semver": "^7.1.1" } }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "npm-package-arg": { "version": "9.1.0", "bundled": true, - "dev": true, "requires": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -43897,7 +43538,6 @@ "npm-packlist": { "version": "5.1.3", "bundled": true, - "dev": true, "requires": { "glob": "^8.0.1", "ignore-walk": "^5.0.1", @@ -43907,15 +43547,13 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true } } }, "npm-pick-manifest": { "version": "7.0.2", "bundled": true, - "dev": true, "requires": { "npm-install-checks": "^5.0.0", "npm-normalize-package-bin": "^2.0.0", @@ -43925,15 +43563,13 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true } } }, "npm-profile": { "version": "6.2.1", "bundled": true, - "dev": true, "requires": { "npm-registry-fetch": "^13.0.1", "proc-log": "^2.0.0" @@ -43942,7 +43578,6 @@ "npm-registry-fetch": { "version": "13.3.1", "bundled": true, - "dev": true, "requires": { "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", @@ -43955,13 +43590,11 @@ }, "npm-user-validate": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "npmlog": { "version": "6.0.2", "bundled": true, - "dev": true, "requires": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -43972,20 +43605,17 @@ "once": { "version": "1.4.0", "bundled": true, - "dev": true, "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.2", - "bundled": true, - "dev": true + "bundled": true }, "p-map": { "version": "4.0.0", "bundled": true, - "dev": true, "requires": { "aggregate-error": "^3.0.0" } @@ -43993,7 +43623,6 @@ "pacote": { "version": "13.6.2", "bundled": true, - "dev": true, "requires": { "@npmcli/git": "^3.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -44021,7 +43650,6 @@ "parse-conflict-json": { "version": "2.0.2", "bundled": true, - "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.1", "just-diff": "^5.0.1", @@ -44030,13 +43658,11 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "postcss-selector-parser": { "version": "6.0.10", "bundled": true, - "dev": true, "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -44044,28 +43670,23 @@ }, "proc-log": { "version": "2.0.1", - "bundled": true, - "dev": true + "bundled": true }, "promise-all-reject-late": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "promise-call-limit": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "promise-inflight": { "version": "1.0.1", - "bundled": true, - "dev": true + "bundled": true }, "promise-retry": { "version": "2.0.1", "bundled": true, - "dev": true, "requires": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -44074,33 +43695,28 @@ "promzard": { "version": "0.3.0", "bundled": true, - "dev": true, "requires": { "read": "1" } }, "qrcode-terminal": { "version": "0.12.0", - "bundled": true, - "dev": true + "bundled": true }, "read": { "version": "1.0.7", "bundled": true, - "dev": true, "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "3.0.0", - "bundled": true, - "dev": true + "bundled": true }, "read-package-json": { "version": "5.0.2", "bundled": true, - "dev": true, "requires": { "glob": "^8.0.1", "json-parse-even-better-errors": "^2.3.1", @@ -44110,15 +43726,13 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true } } }, "read-package-json-fast": { "version": "2.0.3", "bundled": true, - "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" @@ -44127,7 +43741,6 @@ "readable-stream": { "version": "3.6.0", "bundled": true, - "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -44137,7 +43750,6 @@ "readdir-scoped-modules": { "version": "1.1.0", "bundled": true, - "dev": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -44147,13 +43759,11 @@ }, "retry": { "version": "0.12.0", - "bundled": true, - "dev": true + "bundled": true }, "rimraf": { "version": "3.0.2", "bundled": true, - "dev": true, "requires": { "glob": "^7.1.3" }, @@ -44161,7 +43771,6 @@ "brace-expansion": { "version": "1.1.11", "bundled": true, - "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -44170,7 +43779,6 @@ "glob": { "version": "7.2.3", "bundled": true, - "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -44183,7 +43791,6 @@ "minimatch": { "version": "3.1.2", "bundled": true, - "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -44192,19 +43799,15 @@ }, "safe-buffer": { "version": "5.2.1", - "bundled": true, - "dev": true + "bundled": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true + "bundled": true }, "semver": { "version": "7.3.7", "bundled": true, - "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -44212,7 +43815,6 @@ "lru-cache": { "version": "6.0.0", "bundled": true, - "dev": true, "requires": { "yallist": "^4.0.0" } @@ -44221,23 +43823,19 @@ }, "set-blocking": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "signal-exit": { "version": "3.0.7", - "bundled": true, - "dev": true + "bundled": true }, "smart-buffer": { "version": "4.2.0", - "bundled": true, - "dev": true + "bundled": true }, "socks": { "version": "2.7.0", "bundled": true, - "dev": true, "requires": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -44246,7 +43844,6 @@ "socks-proxy-agent": { "version": "7.0.0", "bundled": true, - "dev": true, "requires": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -44256,7 +43853,6 @@ "spdx-correct": { "version": "3.1.1", "bundled": true, - "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -44264,13 +43860,11 @@ }, "spdx-exceptions": { "version": "2.3.0", - "bundled": true, - "dev": true + "bundled": true }, "spdx-expression-parse": { "version": "3.0.1", "bundled": true, - "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -44278,13 +43872,11 @@ }, "spdx-license-ids": { "version": "3.0.11", - "bundled": true, - "dev": true + "bundled": true }, "ssri": { "version": "9.0.1", "bundled": true, - "dev": true, "requires": { "minipass": "^3.1.1" } @@ -44292,7 +43884,6 @@ "string_decoder": { "version": "1.3.0", "bundled": true, - "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -44300,7 +43891,6 @@ "string-width": { "version": "4.2.3", "bundled": true, - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -44310,7 +43900,6 @@ "strip-ansi": { "version": "6.0.1", "bundled": true, - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -44318,7 +43907,6 @@ "supports-color": { "version": "7.2.0", "bundled": true, - "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -44326,7 +43914,6 @@ "tar": { "version": "6.1.11", "bundled": true, - "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -44338,23 +43925,19 @@ }, "text-table": { "version": "0.2.0", - "bundled": true, - "dev": true + "bundled": true }, "tiny-relative-date": { "version": "1.3.0", - "bundled": true, - "dev": true + "bundled": true }, "treeverse": { "version": "2.0.0", - "bundled": true, - "dev": true + "bundled": true }, "unique-filename": { "version": "2.0.1", "bundled": true, - "dev": true, "requires": { "unique-slug": "^3.0.0" } @@ -44362,20 +43945,17 @@ "unique-slug": { "version": "3.0.0", "bundled": true, - "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, "util-deprecate": { "version": "1.0.2", - "bundled": true, - "dev": true + "bundled": true }, "validate-npm-package-license": { "version": "3.0.4", "bundled": true, - "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -44384,20 +43964,17 @@ "validate-npm-package-name": { "version": "4.0.0", "bundled": true, - "dev": true, "requires": { "builtins": "^5.0.0" } }, "walk-up-path": { "version": "1.0.0", - "bundled": true, - "dev": true + "bundled": true }, "wcwidth": { "version": "1.0.1", "bundled": true, - "dev": true, "requires": { "defaults": "^1.0.3" } @@ -44405,7 +43982,6 @@ "which": { "version": "2.0.2", "bundled": true, - "dev": true, "requires": { "isexe": "^2.0.0" } @@ -44413,20 +43989,17 @@ "wide-align": { "version": "1.1.5", "bundled": true, - "dev": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "wrappy": { "version": "1.0.2", - "bundled": true, - "dev": true + "bundled": true }, "write-file-atomic": { "version": "4.0.2", "bundled": true, - "dev": true, "requires": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -44434,8 +44007,7 @@ }, "yallist": { "version": "4.0.0", - "bundled": true, - "dev": true + "bundled": true } } }, diff --git a/src/CoreManager.js b/src/CoreManager.ts similarity index 74% rename from src/CoreManager.js rename to src/CoreManager.ts index 60467e2a6..577d1796c 100644 --- a/src/CoreManager.js +++ b/src/CoreManager.ts @@ -1,7 +1,3 @@ -/* - * @flow - */ - import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMutations'; import type ParseFile from './ParseFile'; import type { FileSource } from './ParseFile'; @@ -12,134 +8,144 @@ import type ParseUser from './ParseUser'; import type { AuthData } from './ParseUser'; import type { PushData } from './Push'; import type { RequestOptions, FullOptions } from './RESTController'; +import type ParseSession from './ParseSession'; +import type { HookDeclaration, HookDeleteArg } from './ParseHooks'; +import type ParseConfig from './ParseConfig'; type AnalyticsController = { - track: (name: string, dimensions: { [key: string]: string }) => Promise, + track: (name: string, dimensions: { [key: string]: string }) => Promise, }; type CloudController = { - run: (name: string, data: mixed, options: RequestOptions) => Promise, - getJobsData: (options: RequestOptions) => Promise, - startJob: (name: string, data: mixed, options: RequestOptions) => Promise, + run: (name: string, data: any, options: RequestOptions) => Promise, + getJobsData: (options: RequestOptions) => Promise, + startJob: (name: string, data: any, options: RequestOptions) => Promise, }; type ConfigController = { - current: () => Promise, - get: () => Promise, - save: (attrs: { [key: string]: any }) => Promise, + current: () => Promise, + get: (opts?: RequestOptions) => Promise, + save: (attrs: { [key: string]: any }, masterKeyOnlyFlags?: { [key: string]: any }) => Promise, }; type CryptoController = { encrypt: (obj: any, secretKey: string) => string, decrypt: (encryptedText: string, secretKey: any) => string, }; type FileController = { - saveFile: (name: string, source: FileSource, options: FullOptions) => Promise, - saveBase64: (name: string, source: FileSource, options: FullOptions) => Promise, - download: (uri: string) => Promise, + saveFile: (name: string, source: FileSource, options: FullOptions) => Promise, + saveBase64: (name: string, source: FileSource, options: FullOptions) => Promise<{ name: string, url: string }>, + download: (uri: string, options?: any) => Promise<{ base64?: string, contentType?: string }>, + deleteFile: (name: string, options?: { useMasterKey?: boolean }) => Promise, }; type InstallationController = { - currentInstallationId: () => Promise, + currentInstallationId: () => Promise, }; type ObjectController = { fetch: ( object: ParseObject | Array, forceFetch: boolean, options: RequestOptions - ) => Promise, - save: (object: ParseObject | Array, options: RequestOptions) => Promise, - destroy: (object: ParseObject | Array, options: RequestOptions) => Promise, + ) => Promise, + save: (object: ParseObject | Array, options: RequestOptions) => Promise | ParseFile>, + destroy: (object: ParseObject | Array, options: RequestOptions) => Promise>, }; type ObjectStateController = { - getState: (obj: any) => ?State, + getState: (obj: any) => State | undefined, initializeState: (obj: any, initial?: State) => State, - removeState: (obj: any) => ?State, + removeState: (obj: any) => State | undefined, getServerData: (obj: any) => AttributeMap, setServerData: (obj: any, attributes: AttributeMap) => void, getPendingOps: (obj: any) => Array, - setPendingOp: (obj: any, attr: string, op: ?Op) => void, + setPendingOp: (obj: any, attr: string, op?: Op) => void, pushPendingState: (obj: any) => void, popPendingState: (obj: any) => OpsMap, mergeFirstPendingState: (obj: any) => void, getObjectCache: (obj: any) => ObjectCache, - estimateAttribute: (obj: any, attr: string) => mixed, + estimateAttribute: (obj: any, attr: string) => any, estimateAttributes: (obj: any) => AttributeMap, commitServerChanges: (obj: any, changes: AttributeMap) => void, - enqueueTask: (obj: any, task: () => Promise) => Promise, + enqueueTask: (obj: any, task: () => Promise) => Promise, clearAllState: () => void, duplicateState: (source: any, dest: any) => void, }; type PushController = { - send: (data: PushData) => Promise, + send: (data: PushData) => Promise, }; type QueryController = { - find: (className: string, params: QueryJSON, options: RequestOptions) => Promise, - aggregate: (className: string, params: any, options: RequestOptions) => Promise, + find: (className: string, params: QueryJSON, options: RequestOptions) => Promise, + aggregate: (className: string, params: any, options: RequestOptions) => Promise, }; type RESTController = { - request: (method: string, path: string, data: mixed, options: RequestOptions) => Promise, - ajax: (method: string, url: string, data: any, headers?: any, options: FullOptions) => Promise, + request: (method: string, path: string, data: any, options: RequestOptions) => Promise, + ajax: (method: string, url: string, data: any, headers?: any, options?: FullOptions) => Promise, + handleError: (err?: any) => void, }; type SchemaController = { - purge: (className: string) => Promise, - get: (className: string, options: RequestOptions) => Promise, - delete: (className: string, options: RequestOptions) => Promise, - create: (className: string, params: any, options: RequestOptions) => Promise, - update: (className: string, params: any, options: RequestOptions) => Promise, - send(className: string, method: string, params: any, options: RequestOptions): Promise, + purge: (className: string) => Promise, + get: (className: string, options?: RequestOptions) => Promise, + delete: (className: string, options?: RequestOptions) => Promise, + create: (className: string, params: any, options?: RequestOptions) => Promise, + update: (className: string, params: any, options?: RequestOptions) => Promise, + send(className: string, method: string, params: any, options: RequestOptions): Promise, }; type SessionController = { - getSession: (token: RequestOptions) => Promise, + getSession: (token: RequestOptions) => Promise, }; type StorageController = | { - async: 0, - getItem: (path: string) => ?string, - setItem: (path: string, value: string) => void, - removeItem: (path: string) => void, - getItemAsync?: (path: string) => Promise, - setItemAsync?: (path: string, value: string) => Promise, - removeItemAsync?: (path: string) => Promise, - clear: () => void, - } + async: 0, + getItem: (path: string) => string | null, + setItem: (path: string, value: string) => void, + removeItem: (path: string) => void, + getItemAsync?: (path: string) => Promise, + setItemAsync?: (path: string, value: string) => Promise, + removeItemAsync?: (path: string) => Promise, + clear: () => void, + getAllKeys?: () => Array + getAllKeysAsync?: () => Promise> + } | { - async: 1, - getItem?: (path: string) => ?string, - setItem?: (path: string, value: string) => void, - removeItem?: (path: string) => void, - getItemAsync: (path: string) => Promise, - setItemAsync: (path: string, value: string) => Promise, - removeItemAsync: (path: string) => Promise, - clear: () => void, - }; + async: 1, + getItem?: (path: string) => string | null, + setItem?: (path: string, value: string) => void, + removeItem?: (path: string) => void, + getItemAsync: (path: string) => Promise, + setItemAsync: (path: string, value: string) => Promise, + removeItemAsync: (path: string) => Promise, + clear: () => void, + getAllKeys?: () => Array + getAllKeysAsync?: () => Promise> + }; type LocalDatastoreController = { - fromPinWithName: (name: string) => ?any, + fromPinWithName: (name: string) => any | undefined, pinWithName: (name: string, objects: any) => void, unPinWithName: (name: string) => void, - getAllContents: () => ?any, + getAllContents: () => any | undefined, clear: () => void, }; type UserController = { - setCurrentUser: (user: ParseUser) => Promise, - currentUser: () => ?ParseUser, - currentUserAsync: () => Promise, - signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise, - logIn: (user: ParseUser, options: RequestOptions) => Promise, - become: (options: RequestOptions) => Promise, - hydrate: (userJSON: AttributeMap) => Promise, - logOut: (options: RequestOptions) => Promise, - me: (options: RequestOptions) => Promise, - requestPasswordReset: (email: string, options: RequestOptions) => Promise, - updateUserOnDisk: (user: ParseUser) => Promise, - upgradeToRevocableSession: (user: ParseUser, options: RequestOptions) => Promise, - linkWith: (user: ParseUser, authData: AuthData) => Promise, - removeUserFromDisk: () => Promise, - verifyPassword: (username: string, password: string, options: RequestOptions) => Promise, - requestEmailVerification: (email: string, options: RequestOptions) => Promise, + setCurrentUser: (user: ParseUser) => Promise, + currentUser: () => ParseUser | undefined, + currentUserAsync: () => Promise, + signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise, + logIn: (user: ParseUser, options: RequestOptions) => Promise, + become: (options: RequestOptions) => Promise, + hydrate: (userJSON: AttributeMap) => Promise, + logOut: (options: RequestOptions) => Promise, + me: (options: RequestOptions) => Promise, + requestPasswordReset: (email: string, options: RequestOptions) => Promise, + updateUserOnDisk: (user: ParseUser) => Promise, + upgradeToRevocableSession: (user: ParseUser, options: RequestOptions) => Promise, + linkWith: (user: ParseUser, authData: AuthData) => Promise, + removeUserFromDisk: () => Promise, + verifyPassword: (username: string, password: string, options: RequestOptions) => Promise, + requestEmailVerification: (email: string, options: RequestOptions) => Promise, }; type HooksController = { - get: (type: string, functionName?: string, triggerName?: string) => Promise, - create: (hook: mixed) => Promise, - delete: (hook: mixed) => Promise, - update: (hook: mixed) => Promise, - send: (method: string, path: string, body?: mixed) => Promise, + get: (type: string, functionName?: string, triggerName?: string) => Promise, + create: (hook: HookDeclaration) => Promise, + remove: (hook: HookDeleteArg) => Promise, + update: (hook: HookDeclaration) => Promise, + // Renamed to sendRequest since ParseHooks file & tests file uses this. (originally declared as just "send") + sendRequest?: (method: string, path: string, body?: any) => Promise, }; type WebSocketController = { onopen: () => void, @@ -169,7 +175,7 @@ type Config = { WebSocketController?: WebSocketController, }; -const config: Config & { [key: string]: mixed } = { +const config: Config & { [key: string]: any } = { // Defaults IS_NODE: typeof process !== 'undefined' && diff --git a/src/EventEmitter.js b/src/EventEmitter.js deleted file mode 100644 index 1f1bcbd00..000000000 --- a/src/EventEmitter.js +++ /dev/null @@ -1,20 +0,0 @@ -/** - * This is a simple wrapper to unify EventEmitter implementations across platforms. - */ - -let EventEmitter; - -try { - if (process.env.PARSE_BUILD === 'react-native') { - EventEmitter = require('react-native/Libraries/vendor/emitter/EventEmitter'); - if (EventEmitter.default) { - EventEmitter = EventEmitter.default; - } - EventEmitter.prototype.on = EventEmitter.prototype.addListener; - } else { - EventEmitter = require('events').EventEmitter; - } -} catch (_) { - // EventEmitter unavailable -} -module.exports = EventEmitter; diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts new file mode 100644 index 000000000..8e313f092 --- /dev/null +++ b/src/EventEmitter.ts @@ -0,0 +1,25 @@ +import type { EventEmitter as EventEmitterType } from 'events'; +/** + * This is a simple wrapper to unify EventEmitter implementations across platforms. + */ + +let EventEmitter: new (...args: ConstructorParameters) => EventEmitterType; + +try { + if (process.env.PARSE_BUILD === 'react-native') { + let RNEventEmitter = require('react-native/Libraries/vendor/emitter/EventEmitter'); + if (RNEventEmitter.default) { + EventEmitter = RNEventEmitter.default; + } + else { + EventEmitter = RNEventEmitter; + } + (EventEmitter as any).prototype.on = RNEventEmitter.prototype.addListener; + } else { + EventEmitter = require('events').EventEmitter; + } +} catch (_) { + // EventEmitter unavailable +} +module.exports = EventEmitter; +export default EventEmitter; \ No newline at end of file diff --git a/src/LiveQuerySubscription.js b/src/LiveQuerySubscription.ts similarity index 86% rename from src/LiveQuerySubscription.js rename to src/LiveQuerySubscription.ts index c70d234c1..5e7764b67 100644 --- a/src/LiveQuerySubscription.js +++ b/src/LiveQuerySubscription.ts @@ -1,4 +1,6 @@ +import type { EventEmitter } from 'events'; import CoreManager from './CoreManager'; +import AnEventEmitter from './EventEmitter'; import { resolvingPromise } from './promiseUtils'; /** @@ -84,26 +86,36 @@ import { resolvingPromise } from './promiseUtils'; * });

*/ class Subscription { - /* + id: string; + query: string; + sessionToken?: string; + subscribePromise: ReturnType; + unsubscribePromise: ReturnType; + subscribed: boolean; + emitter: EventEmitter; + on: EventEmitter['on']; + emit: EventEmitter['emit']; + + /** * @param {string} id - subscription id * @param {string} query - query to subscribe to * @param {string} sessionToken - optional session token */ - constructor(id, query, sessionToken) { + constructor(id: string, query: string, sessionToken?: string) { this.id = id; this.query = query; this.sessionToken = sessionToken; this.subscribePromise = resolvingPromise(); this.unsubscribePromise = resolvingPromise(); this.subscribed = false; - const EventEmitter = CoreManager.getEventEmitter(); + const EventEmitter = CoreManager.getEventEmitter() as new () => EventEmitter; this.emitter = new EventEmitter(); this.on = this.emitter.on; this.emit = this.emitter.emit; // adding listener so process does not crash // best practice is for developer to register their own listener - this.on('error', () => {}); + this.on('error', () => { }); } /** @@ -111,7 +123,7 @@ class Subscription { * * @returns {Promise} */ - unsubscribe(): Promise { + unsubscribe(): Promise { return CoreManager.getLiveQueryController() .getDefaultLiveQueryClient() .then(liveQueryClient => { diff --git a/src/LocalDatastoreUtils.js b/src/LocalDatastoreUtils.ts similarity index 100% rename from src/LocalDatastoreUtils.js rename to src/LocalDatastoreUtils.ts diff --git a/src/ObjectStateMutations.js b/src/ObjectStateMutations.ts similarity index 98% rename from src/ObjectStateMutations.js rename to src/ObjectStateMutations.ts index d594d5d70..8e4003358 100644 --- a/src/ObjectStateMutations.js +++ b/src/ObjectStateMutations.ts @@ -43,7 +43,7 @@ export function setServerData(serverData: AttributeMap, attributes: AttributeMap } } -export function setPendingOp(pendingOps: Array, attr: string, op: ?Op) { +export function setPendingOp(pendingOps: Array, attr: string, op?: Op) { const last = pendingOps.length - 1; if (op) { pendingOps[last][attr] = op; @@ -83,9 +83,9 @@ export function estimateAttribute( serverData: AttributeMap, pendingOps: Array, className: string, - id: ?string, - attr: string -): mixed { + id: string|undefined, + attr: string|undefined +): any { let value = serverData[attr]; for (let i = 0; i < pendingOps.length; i++) { if (pendingOps[i][attr]) { @@ -105,7 +105,7 @@ export function estimateAttributes( serverData: AttributeMap, pendingOps: Array, className: string, - id: ?string + id?: string ): AttributeMap { const data = {}; let attr; diff --git a/src/ParseCLP.js b/src/ParseCLP.ts similarity index 96% rename from src/ParseCLP.js rename to src/ParseCLP.ts index ff86e387a..c9547436f 100644 --- a/src/ParseCLP.js +++ b/src/ParseCLP.ts @@ -5,9 +5,9 @@ import ParseRole from './ParseRole'; import ParseUser from './ParseUser'; -type Entity = Entity; +type Entity = ParseUser | ParseRole | string; type UsersMap = { [userId: string]: boolean | any }; -export type PermissionsMap = { [permission: string]: UsersMap }; +export type PermissionsMap = { writeUserFields?: string[], readUserFields?: string[], [permission: string]: UsersMap }; const PUBLIC_KEY = '*'; @@ -323,7 +323,7 @@ class ParseCLP { return permissions; } - _setArrayAccess(permission: string, userId: Entity, fields: string) { + _setArrayAccess(permission: string, userId: Entity, fields: string | string[]) { userId = this._parseEntity(userId); const permissions = this.permissionsMap[permission][userId]; @@ -356,7 +356,7 @@ class ParseCLP { } } - _getGroupPointerPermissions(operation: string): string[] { + _getGroupPointerPermissions(operation: 'readUserFields' | 'writeUserFields'): string[] { return this.permissionsMap[operation]; } @@ -409,7 +409,7 @@ class ParseCLP { * @returns {string[]} */ getProtectedFields(userId: Entity): string[] { - return this._getAccess('protectedFields', userId, false); + return this._getAccess('protectedFields', userId, false) as string[]; } /** @@ -435,9 +435,9 @@ class ParseCLP { */ getReadAccess(userId: Entity): boolean { return ( - this._getAccess('find', userId) && - this._getAccess('get', userId) && - this._getAccess('count', userId) + this._getAccess('find', userId) as boolean && + this._getAccess('get', userId) as boolean && + this._getAccess('count', userId) as boolean ); } @@ -465,10 +465,10 @@ class ParseCLP { */ getWriteAccess(userId: Entity): boolean { return ( - this._getAccess('create', userId) && - this._getAccess('update', userId) && - this._getAccess('delete', userId) && - this._getAccess('addField', userId) + this._getAccess('create', userId) as boolean && + this._getAccess('update', userId) as boolean && + this._getAccess('delete', userId) as boolean && + this._getAccess('addField', userId) as boolean ); } diff --git a/src/ParseConfig.js b/src/ParseConfig.ts similarity index 98% rename from src/ParseConfig.js rename to src/ParseConfig.ts index 57620deb6..d39e97e70 100644 --- a/src/ParseConfig.js +++ b/src/ParseConfig.ts @@ -18,7 +18,7 @@ import type { RequestOptions } from './RESTController'; * @alias Parse.Config */ -class ParseConfig { +export class ParseConfig { attributes: { [key: string]: any }; _escapedAttributes: { [key: string]: any }; @@ -123,7 +123,7 @@ class ParseConfig { } } -let currentConfig = null; +let currentConfig: ParseConfig | null = null; const CURRENT_CONFIG_KEY = 'currentConfig'; @@ -139,7 +139,7 @@ function decodePayload(data) { } const DefaultController = { - current() { + current: async ()=> { if (currentConfig) { return currentConfig; } diff --git a/src/ParseError.js b/src/ParseError.js deleted file mode 100644 index 68c97501e..000000000 --- a/src/ParseError.js +++ /dev/null @@ -1,551 +0,0 @@ -import CoreManager from './CoreManager'; - -/** - * Constructs a new Parse.Error object with the given code and message. - * - * Parse.CoreManager.set('PARSE_ERRORS', [{ code, message }]) can be use to override error messages. - * - * @alias Parse.Error - */ -class ParseError extends Error { - /** - * @param {number} code An error code constant from Parse.Error. - * @param {string} message A detailed description of the error. - */ - constructor(code, message) { - super(message); - this.code = code; - let customMessage = message; - CoreManager.get('PARSE_ERRORS').forEach((error) => { - if (error.code === code && error.code) { - customMessage = error.message; - } - }); - Object.defineProperty(this, 'message', { - enumerable: true, - value: customMessage, - }); - } - - toString() { - return 'ParseError: ' + this.code + ' ' + this.message; - } -} - -/** - * Error code indicating some error other than those enumerated here. - * - * @property {number} OTHER_CAUSE - * @static - */ -ParseError.OTHER_CAUSE = -1; - -/** - * Error code indicating that something has gone wrong with the server. - * - * @property {number} INTERNAL_SERVER_ERROR - * @static - */ -ParseError.INTERNAL_SERVER_ERROR = 1; - -/** - * Error code indicating the connection to the Parse servers failed. - * - * @property {number} CONNECTION_FAILED - * @static - */ -ParseError.CONNECTION_FAILED = 100; - -/** - * Error code indicating the specified object doesn't exist. - * - * @property {number} OBJECT_NOT_FOUND - * @static - */ -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 {number} INVALID_QUERY - * @static - */ -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 {number} INVALID_CLASS_NAME - * @static - */ -ParseError.INVALID_CLASS_NAME = 103; - -/** - * Error code indicating an unspecified object id. - * - * @property {number} MISSING_OBJECT_ID - * @static - */ -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 {number} INVALID_KEY_NAME - * @static - */ -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 {number} INVALID_POINTER - * @static - */ -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 {number} INVALID_JSON - * @static - */ -ParseError.INVALID_JSON = 107; - -/** - * Error code indicating that the feature you tried to access is only - * available internally for testing purposes. - * - * @property {number} COMMAND_UNAVAILABLE - * @static - */ -ParseError.COMMAND_UNAVAILABLE = 108; - -/** - * You must call Parse.initialize before using the Parse library. - * - * @property {number} NOT_INITIALIZED - * @static - */ -ParseError.NOT_INITIALIZED = 109; - -/** - * Error code indicating that a field was set to an inconsistent type. - * - * @property {number} INCORRECT_TYPE - * @static - */ -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 {number} INVALID_CHANNEL_NAME - * @static - */ -ParseError.INVALID_CHANNEL_NAME = 112; - -/** - * Error code indicating that push is misconfigured. - * - * @property {number} PUSH_MISCONFIGURED - * @static - */ -ParseError.PUSH_MISCONFIGURED = 115; - -/** - * Error code indicating that the object is too large. - * - * @property {number} OBJECT_TOO_LARGE - * @static - */ -ParseError.OBJECT_TOO_LARGE = 116; - -/** - * Error code indicating that the operation isn't allowed for clients. - * - * @property {number} OPERATION_FORBIDDEN - * @static - */ -ParseError.OPERATION_FORBIDDEN = 119; - -/** - * Error code indicating the result was not found in the cache. - * - * @property {number} CACHE_MISS - * @static - */ -ParseError.CACHE_MISS = 120; - -/** - * Error code indicating that an invalid key was used in a nested - * JSONObject. - * - * @property {number} INVALID_NESTED_KEY - * @static - */ -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 {number} INVALID_FILE_NAME - * @static - */ -ParseError.INVALID_FILE_NAME = 122; - -/** - * Error code indicating an invalid ACL was provided. - * - * @property {number} INVALID_ACL - * @static - */ -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 {number} TIMEOUT - * @static - */ -ParseError.TIMEOUT = 124; - -/** - * Error code indicating that the email address was invalid. - * - * @property {number} INVALID_EMAIL_ADDRESS - * @static - */ -ParseError.INVALID_EMAIL_ADDRESS = 125; - -/** - * Error code indicating a missing content type. - * - * @property {number} MISSING_CONTENT_TYPE - * @static - */ -ParseError.MISSING_CONTENT_TYPE = 126; - -/** - * Error code indicating a missing content length. - * - * @property {number} MISSING_CONTENT_LENGTH - * @static - */ -ParseError.MISSING_CONTENT_LENGTH = 127; - -/** - * Error code indicating an invalid content length. - * - * @property {number} INVALID_CONTENT_LENGTH - * @static - */ -ParseError.INVALID_CONTENT_LENGTH = 128; - -/** - * Error code indicating a file that was too large. - * - * @property {number} FILE_TOO_LARGE - * @static - */ -ParseError.FILE_TOO_LARGE = 129; - -/** - * Error code indicating an error saving a file. - * - * @property {number} FILE_SAVE_ERROR - * @static - */ -ParseError.FILE_SAVE_ERROR = 130; - -/** - * Error code indicating that a unique field was given a value that is - * already taken. - * - * @property {number} DUPLICATE_VALUE - * @static - */ -ParseError.DUPLICATE_VALUE = 137; - -/** - * Error code indicating that a role's name is invalid. - * - * @property {number} INVALID_ROLE_NAME - * @static - */ -ParseError.INVALID_ROLE_NAME = 139; - -/** - * Error code indicating that an application quota was exceeded. Upgrade to - * resolve. - * - * @property {number} EXCEEDED_QUOTA - * @static - */ -ParseError.EXCEEDED_QUOTA = 140; - -/** - * Error code indicating that a Cloud Code script failed. - * - * @property {number} SCRIPT_FAILED - * @static - */ -ParseError.SCRIPT_FAILED = 141; - -/** - * Error code indicating that a Cloud Code validation failed. - * - * @property {number} VALIDATION_ERROR - * @static - */ -ParseError.VALIDATION_ERROR = 142; - -/** - * Error code indicating that invalid image data was provided. - * - * @property {number} INVALID_IMAGE_DATA - * @static - */ -ParseError.INVALID_IMAGE_DATA = 143; - -/** - * Error code indicating an unsaved file. - * - * @property {number} UNSAVED_FILE_ERROR - * @static - */ -ParseError.UNSAVED_FILE_ERROR = 151; - -/** - * Error code indicating an invalid push time. - * - * @property {number} INVALID_PUSH_TIME_ERROR - * @static - */ -ParseError.INVALID_PUSH_TIME_ERROR = 152; - -/** - * Error code indicating an error deleting a file. - * - * @property {number} FILE_DELETE_ERROR - * @static - */ -ParseError.FILE_DELETE_ERROR = 153; - -/** - * Error code indicating an error deleting an unnamed file. - * - * @property {number} FILE_DELETE_UNNAMED_ERROR - * @static - */ -ParseError.FILE_DELETE_UNNAMED_ERROR = 161; - -/** - * Error code indicating that the application has exceeded its request - * limit. - * - * @property {number} REQUEST_LIMIT_EXCEEDED - * @static - */ -ParseError.REQUEST_LIMIT_EXCEEDED = 155; - -/** - * Error code indicating that the request was a duplicate and has been discarded due to - * idempotency rules. - * - * @property {number} DUPLICATE_REQUEST - * @static - */ -ParseError.DUPLICATE_REQUEST = 159; - -/** - * Error code indicating an invalid event name. - * - * @property {number} INVALID_EVENT_NAME - * @static - */ -ParseError.INVALID_EVENT_NAME = 160; - -/** - * Error code indicating that a field had an invalid value. - * - * @property {number} INVALID_VALUE - * @static - */ -ParseError.INVALID_VALUE = 162; - -/** - * Error code indicating that the username is missing or empty. - * - * @property {number} USERNAME_MISSING - * @static - */ -ParseError.USERNAME_MISSING = 200; - -/** - * Error code indicating that the password is missing or empty. - * - * @property {number} PASSWORD_MISSING - * @static - */ -ParseError.PASSWORD_MISSING = 201; - -/** - * Error code indicating that the username has already been taken. - * - * @property {number} USERNAME_TAKEN - * @static - */ -ParseError.USERNAME_TAKEN = 202; - -/** - * Error code indicating that the email has already been taken. - * - * @property {number} EMAIL_TAKEN - * @static - */ -ParseError.EMAIL_TAKEN = 203; - -/** - * Error code indicating that the email is missing, but must be specified. - * - * @property {number} EMAIL_MISSING - * @static - */ -ParseError.EMAIL_MISSING = 204; - -/** - * Error code indicating that a user with the specified email was not found. - * - * @property {number} EMAIL_NOT_FOUND - * @static - */ -ParseError.EMAIL_NOT_FOUND = 205; - -/** - * Error code indicating that a user object without a valid session could - * not be altered. - * - * @property {number} SESSION_MISSING - * @static - */ -ParseError.SESSION_MISSING = 206; - -/** - * Error code indicating that a user can only be created through signup. - * - * @property {number} MUST_CREATE_USER_THROUGH_SIGNUP - * @static - */ -ParseError.MUST_CREATE_USER_THROUGH_SIGNUP = 207; - -/** - * Error code indicating that an an account being linked is already linked - * to another user. - * - * @property {number} ACCOUNT_ALREADY_LINKED - * @static - */ -ParseError.ACCOUNT_ALREADY_LINKED = 208; - -/** - * Error code indicating that the current session token is invalid. - * - * @property {number} INVALID_SESSION_TOKEN - * @static - */ -ParseError.INVALID_SESSION_TOKEN = 209; - -/** - * Error code indicating an error enabling or verifying MFA - * - * @property {number} MFA_ERROR - * @static - */ -ParseError.MFA_ERROR = 210; - -/** - * Error code indicating that a valid MFA token must be provided - * - * @property {number} MFA_TOKEN_REQUIRED - * @static - */ -ParseError.MFA_TOKEN_REQUIRED = 211; - -/** - * Error code indicating that a user cannot be linked to an account because - * that account's id could not be found. - * - * @property {number} LINKED_ID_MISSING - * @static - */ -ParseError.LINKED_ID_MISSING = 250; - -/** - * Error code indicating that a user with a linked (e.g. Facebook) account - * has an invalid session. - * - * @property {number} INVALID_LINKED_SESSION - * @static - */ -ParseError.INVALID_LINKED_SESSION = 251; - -/** - * Error code indicating that a service being linked (e.g. Facebook or - * Twitter) is unsupported. - * - * @property {number} UNSUPPORTED_SERVICE - * @static - */ -ParseError.UNSUPPORTED_SERVICE = 252; - -/** - * Error code indicating an invalid operation occured on schema - * - * @property {number} INVALID_SCHEMA_OPERATION - * @static - */ -ParseError.INVALID_SCHEMA_OPERATION = 255; - -/** - * 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 {number} AGGREGATE_ERROR - * @static - */ -ParseError.AGGREGATE_ERROR = 600; - -/** - * Error code indicating the client was unable to read an input file. - * - * @property {number} FILE_READ_ERROR - * @static - */ -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 {number} X_DOMAIN_REQUEST - * @static - */ -ParseError.X_DOMAIN_REQUEST = 602; - -export default ParseError; diff --git a/src/ParseError.ts b/src/ParseError.ts new file mode 100644 index 000000000..1f8e4e0b1 --- /dev/null +++ b/src/ParseError.ts @@ -0,0 +1,559 @@ +import CoreManager from './CoreManager'; +import type ParseObject from './ParseObject'; + +/** + * Constructs a new Parse.Error object with the given code and message. + * + * Parse.CoreManager.set('PARSE_ERRORS', [{ code, message }]) can be use to override error messages. + * + * @alias Parse.Error + */ +class ParseError extends Error { + code: number; + message: string; + /** In case an error is associated with an object */ + object?: ParseObject; + /** In case of aggregate errors, this is populated */ + errors?: Error[]; + /** + * @param {number} code An error code constant from Parse.Error. + * @param {string} message A detailed description of the error. + */ + constructor(code: number, message?: string) { + super(message); + this.code = code; + let customMessage = message; + CoreManager.get('PARSE_ERRORS').forEach((error: { code: number, message: string }) => { + if (error.code === code && error.code) { + customMessage = error.message; + } + }); + Object.defineProperty(this, 'message', { + enumerable: true, + value: customMessage, + }); + } + + toString() { + return 'ParseError: ' + this.code + ' ' + this.message; + } + + + /** + * Error code indicating some error other than those enumerated here. + * + * @property {number} OTHER_CAUSE + * @static + */ + static OTHER_CAUSE = -1; + + /** + * Error code indicating that something has gone wrong with the server. + * + * @property {number} INTERNAL_SERVER_ERROR + * @static + */ + static INTERNAL_SERVER_ERROR = 1; + + /** + * Error code indicating the connection to the Parse servers failed. + * + * @property {number} CONNECTION_FAILED + * @static + */ + static CONNECTION_FAILED = 100; + + /** + * Error code indicating the specified object doesn't exist. + * + * @property {number} OBJECT_NOT_FOUND + * @static + */ + static 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 {number} INVALID_QUERY + * @static + */ + static 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 {number} INVALID_CLASS_NAME + * @static + */ + static INVALID_CLASS_NAME = 103; + + /** + * Error code indicating an unspecified object id. + * + * @property {number} MISSING_OBJECT_ID + * @static + */ + static 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 {number} INVALID_KEY_NAME + * @static + */ + static 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 {number} INVALID_POINTER + * @static + */ + static 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 {number} INVALID_JSON + * @static + */ + static INVALID_JSON = 107; + + /** + * Error code indicating that the feature you tried to access is only + * available internally for testing purposes. + * + * @property {number} COMMAND_UNAVAILABLE + * @static + */ + static COMMAND_UNAVAILABLE = 108; + + /** + * You must call Parse.initialize before using the Parse library. + * + * @property {number} NOT_INITIALIZED + * @static + */ + static NOT_INITIALIZED = 109; + + /** + * Error code indicating that a field was set to an inconsistent type. + * + * @property {number} INCORRECT_TYPE + * @static + */ + static 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 {number} INVALID_CHANNEL_NAME + * @static + */ + static INVALID_CHANNEL_NAME = 112; + + /** + * Error code indicating that push is misconfigured. + * + * @property {number} PUSH_MISCONFIGURED + * @static + */ + static PUSH_MISCONFIGURED = 115; + + /** + * Error code indicating that the object is too large. + * + * @property {number} OBJECT_TOO_LARGE + * @static + */ + static OBJECT_TOO_LARGE = 116; + + /** + * Error code indicating that the operation isn't allowed for clients. + * + * @property {number} OPERATION_FORBIDDEN + * @static + */ + static OPERATION_FORBIDDEN = 119; + + /** + * Error code indicating the result was not found in the cache. + * + * @property {number} CACHE_MISS + * @static + */ + static CACHE_MISS = 120; + + /** + * Error code indicating that an invalid key was used in a nested + * JSONObject. + * + * @property {number} INVALID_NESTED_KEY + * @static + */ + static 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 {number} INVALID_FILE_NAME + * @static + */ + static INVALID_FILE_NAME = 122; + + /** + * Error code indicating an invalid ACL was provided. + * + * @property {number} INVALID_ACL + * @static + */ + static 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 {number} TIMEOUT + * @static + */ + static TIMEOUT = 124; + + /** + * Error code indicating that the email address was invalid. + * + * @property {number} INVALID_EMAIL_ADDRESS + * @static + */ + static INVALID_EMAIL_ADDRESS = 125; + + /** + * Error code indicating a missing content type. + * + * @property {number} MISSING_CONTENT_TYPE + * @static + */ + static MISSING_CONTENT_TYPE = 126; + + /** + * Error code indicating a missing content length. + * + * @property {number} MISSING_CONTENT_LENGTH + * @static + */ + static MISSING_CONTENT_LENGTH = 127; + + /** + * Error code indicating an invalid content length. + * + * @property {number} INVALID_CONTENT_LENGTH + * @static + */ + static INVALID_CONTENT_LENGTH = 128; + + /** + * Error code indicating a file that was too large. + * + * @property {number} FILE_TOO_LARGE + * @static + */ + static FILE_TOO_LARGE = 129; + + /** + * Error code indicating an error saving a file. + * + * @property {number} FILE_SAVE_ERROR + * @static + */ + static FILE_SAVE_ERROR = 130; + + /** + * Error code indicating that a unique field was given a value that is + * already taken. + * + * @property {number} DUPLICATE_VALUE + * @static + */ + static DUPLICATE_VALUE = 137; + + /** + * Error code indicating that a role's name is invalid. + * + * @property {number} INVALID_ROLE_NAME + * @static + */ + static INVALID_ROLE_NAME = 139; + + /** + * Error code indicating that an application quota was exceeded. Upgrade to + * resolve. + * + * @property {number} EXCEEDED_QUOTA + * @static + */ + static EXCEEDED_QUOTA = 140; + + /** + * Error code indicating that a Cloud Code script failed. + * + * @property {number} SCRIPT_FAILED + * @static + */ + static SCRIPT_FAILED = 141; + + /** + * Error code indicating that a Cloud Code validation failed. + * + * @property {number} VALIDATION_ERROR + * @static + */ + static VALIDATION_ERROR = 142; + + /** + * Error code indicating that invalid image data was provided. + * + * @property {number} INVALID_IMAGE_DATA + * @static + */ + static INVALID_IMAGE_DATA = 143; + + /** + * Error code indicating an unsaved file. + * + * @property {number} UNSAVED_FILE_ERROR + * @static + */ + static UNSAVED_FILE_ERROR = 151; + + /** + * Error code indicating an invalid push time. + * + * @property {number} INVALID_PUSH_TIME_ERROR + * @static + */ + static INVALID_PUSH_TIME_ERROR = 152; + + /** + * Error code indicating an error deleting a file. + * + * @property {number} FILE_DELETE_ERROR + * @static + */ + static FILE_DELETE_ERROR = 153; + + /** + * Error code indicating an error deleting an unnamed file. + * + * @property {number} FILE_DELETE_UNNAMED_ERROR + * @static + */ + static FILE_DELETE_UNNAMED_ERROR = 161; + + /** + * Error code indicating that the application has exceeded its request + * limit. + * + * @property {number} REQUEST_LIMIT_EXCEEDED + * @static + */ + static REQUEST_LIMIT_EXCEEDED = 155; + + /** + * Error code indicating that the request was a duplicate and has been discarded due to + * idempotency rules. + * + * @property {number} DUPLICATE_REQUEST + * @static + */ + static DUPLICATE_REQUEST = 159; + + /** + * Error code indicating an invalid event name. + * + * @property {number} INVALID_EVENT_NAME + * @static + */ + static INVALID_EVENT_NAME = 160; + + /** + * Error code indicating that a field had an invalid value. + * + * @property {number} INVALID_VALUE + * @static + */ + static INVALID_VALUE = 162; + + /** + * Error code indicating that the username is missing or empty. + * + * @property {number} USERNAME_MISSING + * @static + */ + static USERNAME_MISSING = 200; + + /** + * Error code indicating that the password is missing or empty. + * + * @property {number} PASSWORD_MISSING + * @static + */ + static PASSWORD_MISSING = 201; + + /** + * Error code indicating that the username has already been taken. + * + * @property {number} USERNAME_TAKEN + * @static + */ + static USERNAME_TAKEN = 202; + + /** + * Error code indicating that the email has already been taken. + * + * @property {number} EMAIL_TAKEN + * @static + */ + static EMAIL_TAKEN = 203; + + /** + * Error code indicating that the email is missing, but must be specified. + * + * @property {number} EMAIL_MISSING + * @static + */ + static EMAIL_MISSING = 204; + + /** + * Error code indicating that a user with the specified email was not found. + * + * @property {number} EMAIL_NOT_FOUND + * @static + */ + static EMAIL_NOT_FOUND = 205; + + /** + * Error code indicating that a user object without a valid session could + * not be altered. + * + * @property {number} SESSION_MISSING + * @static + */ + static SESSION_MISSING = 206; + + /** + * Error code indicating that a user can only be created through signup. + * + * @property {number} MUST_CREATE_USER_THROUGH_SIGNUP + * @static + */ + static MUST_CREATE_USER_THROUGH_SIGNUP = 207; + + /** + * Error code indicating that an an account being linked is already linked + * to another user. + * + * @property {number} ACCOUNT_ALREADY_LINKED + * @static + */ + static ACCOUNT_ALREADY_LINKED = 208; + + /** + * Error code indicating that the current session token is invalid. + * + * @property {number} INVALID_SESSION_TOKEN + * @static + */ + static INVALID_SESSION_TOKEN = 209; + + /** + * Error code indicating an error enabling or verifying MFA + * + * @property {number} MFA_ERROR + * @static + */ + static MFA_ERROR = 210; + + /** + * Error code indicating that a valid MFA token must be provided + * + * @property {number} MFA_TOKEN_REQUIRED + * @static + */ + static MFA_TOKEN_REQUIRED = 211; + + /** + * Error code indicating that a user cannot be linked to an account because + * that account's id could not be found. + * + * @property {number} LINKED_ID_MISSING + * @static + */ + static LINKED_ID_MISSING = 250; + + /** + * Error code indicating that a user with a linked (e.g. Facebook) account + * has an invalid session. + * + * @property {number} INVALID_LINKED_SESSION + * @static + */ + static INVALID_LINKED_SESSION = 251; + + /** + * Error code indicating that a service being linked (e.g. Facebook or + * Twitter) is unsupported. + * + * @property {number} UNSUPPORTED_SERVICE + * @static + */ + static UNSUPPORTED_SERVICE = 252; + + /** + * Error code indicating an invalid operation occured on schema + * + * @property {number} INVALID_SCHEMA_OPERATION + * @static + */ + static INVALID_SCHEMA_OPERATION = 255; + + /** + * 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 {number} AGGREGATE_ERROR + * @static + */ + static AGGREGATE_ERROR = 600; + + /** + * Error code indicating the client was unable to read an input file. + * + * @property {number} FILE_READ_ERROR + * @static + */ + static 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 {number} X_DOMAIN_REQUEST + * @static + */ + static X_DOMAIN_REQUEST = 602; +} + +export default ParseError; \ No newline at end of file diff --git a/src/ParseFile.js b/src/ParseFile.ts similarity index 89% rename from src/ParseFile.js rename to src/ParseFile.ts index 1d7ff6945..956bf9c65 100644 --- a/src/ParseFile.js +++ b/src/ParseFile.ts @@ -7,7 +7,7 @@ import type { FullOptions } from './RESTController'; const ParseError = require('./ParseError').default; -let XHR = null; +let XHR: typeof XMLHttpRequest = null; if (typeof XMLHttpRequest !== 'undefined') { XHR = XMLHttpRequest; } @@ -20,20 +20,20 @@ type Uri = { uri: string }; type FileData = Array | Base64 | Blob | Uri; export type FileSource = | { - format: 'file', - file: Blob, - type: string, - } + format: 'file', + file: Blob, + type: string, + } | { - format: 'base64', - base64: string, - type: string, - } + format: 'base64', + base64: string, + type: string, + } | { - format: 'uri', - uri: string, - type: string, - }; + format: 'uri', + uri: string, + type: string, + }; function b64Digit(number: number): string { if (number < 26) { @@ -54,6 +54,11 @@ function b64Digit(number: number): string { throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); } +type FileSaveOptions = FullOptions & { + metadata?: { [key: string]: any } + tags?: { [key: string]: any } +} + /** * A Parse.File is a local representation of a file that is saved to the Parse * cloud. @@ -62,13 +67,13 @@ function b64Digit(number: number): string { */ class ParseFile { _name: string; - _url: ?string; + _url?: string; _source: FileSource; - _previousSave: ?Promise; - _data: ?string; - _requestTask: ?any; - _metadata: ?Object; - _tags: ?Object; + _previousSave?: Promise; + _data?: string; + _requestTask?: any; + _metadata?: Object; + _tags?: Object; /** * @param name {String} The file's name. This will be prefixed by a unique @@ -121,17 +126,18 @@ class ParseFile { file: data, type: specifiedType, }; - } else if (data && typeof data.uri === 'string' && data.uri !== undefined) { + } else if (data && typeof (data as Uri).uri === 'string' && (data as Uri).uri !== undefined) { this._source = { format: 'uri', - uri: data.uri, + uri: (data as Uri).uri, type: specifiedType, }; - } else if (data && typeof data.base64 === 'string') { - const base64 = data.base64.split(',').slice(-1)[0]; + } else if (data && typeof (data as Base64).base64 === 'string') { + const b64data = data as Base64; + const base64 = b64data.base64.split(',').slice(-1)[0]; const dataType = specifiedType || - data.base64.split(';').slice(0, 1)[0].split(':').slice(1, 2)[0] || + b64data.base64.split(';').slice(0, 1)[0].split(':').slice(1, 2)[0] || 'text/plain'; this._data = base64; this._source = { @@ -152,7 +158,7 @@ class ParseFile { * * @returns {Promise} Promise that is resolve with base64 data */ - async getData(): Promise { + async getData(): Promise { if (this._data) { return this._data; } @@ -186,7 +192,7 @@ class ParseFile { * @param {object} options An object to specify url options * @returns {string | undefined} */ - url(options?: { forceSecure?: boolean }): ?string { + url(options?: { forceSecure?: boolean }): string | undefined { options = options || {}; if (!this._url) { return; @@ -239,9 +245,9 @@ class ParseFile { * * @returns {Promise | undefined} Promise that is resolved when the save finishes. */ - save(options?: FullOptions): ?Promise { - options = options || {}; - options.requestTask = task => (this._requestTask = task); + save(options?: FileSaveOptions): Promise | undefined { + options = { ...options || {} }; + options.requestTask = (task: any) => (this._requestTask = task); options.metadata = this._metadata; options.tags = this._tags; @@ -263,7 +269,7 @@ class ParseFile { return {}; } const newSource = { - format: 'base64', + format: 'base64' as const, base64: result.base64, type: result.contentType, }; @@ -271,7 +277,7 @@ class ParseFile { this._requestTask = null; return controller.saveBase64(this._name, newSource, options); }) - .then(res => { + .then((res: { name?: string, url?: string }) => { this._name = res.name; this._url = res.url; this._requestTask = null; @@ -313,7 +319,7 @@ class ParseFile { *
    * @returns {Promise} Promise that is resolved when the delete finishes.
    */
-  destroy(options?: FullOptions = {}) {
+  destroy(options: FullOptions = {}) {
     if (!this._name) {
       throw new ParseError(ParseError.FILE_DELETE_UNNAMED_ERROR, 'Cannot delete an unnamed file.');
     }
@@ -329,7 +335,7 @@ class ParseFile {
     });
   }
 
-  toJSON(): { name: ?string, url: ?string } {
+  toJSON(): { __type: 'File', name?: string, url?: string } {
     return {
       __type: 'File',
       name: this._name,
@@ -337,7 +343,7 @@ class ParseFile {
     };
   }
 
-  equals(other: mixed): boolean {
+  equals(other: any): boolean {
     if (this === other) {
       return true;
     }
@@ -409,7 +415,7 @@ class ParseFile {
     return file;
   }
 
-  static encodeBase64(bytes: Array): string {
+  static encodeBase64(bytes: Array | Uint8Array): string {
     const chunks = [];
     chunks.length = Math.ceil(bytes.length / 3);
     for (let i = 0; i < chunks.length; i++) {
@@ -437,10 +443,10 @@ const DefaultController = {
     if (source.format !== 'file') {
       throw new Error('saveFile can only be used with File-type sources.');
     }
-    const base64Data = await new Promise((res, rej) => {
+    const base64Data = await new Promise((res, rej) => {
       // eslint-disable-next-line no-undef
       const reader = new FileReader();
-      reader.onload = () => res(reader.result);
+      reader.onload = () => res(reader.result as string);
       reader.onerror = error => rej(error);
       reader.readAsDataURL(source.file);
     });
@@ -451,14 +457,14 @@ const DefaultController = {
     // use the entire string instead
     const data = second ? second : first;
     const newSource = {
-      format: 'base64',
+      format: 'base64' as const,
       base64: data,
       type: source.type || (source.file ? source.file.type : null),
     };
     return await DefaultController.saveBase64(name, newSource, options);
   },
 
-  saveBase64: function (name: string, source: FileSource, options?: FullOptions) {
+  saveBase64: function (name: string, source: FileSource, options?: FileSaveOptions) {
     if (source.format !== 'base64') {
       throw new Error('saveBase64 can only be used with Base64-type sources.');
     }
@@ -469,16 +475,17 @@ const DefaultController = {
         tags: { ...options.tags },
       },
     };
-    delete options.metadata;
-    delete options.tags;
+    const restOptions = { ...options };
+    delete restOptions.metadata;
+    delete restOptions.tags;
     if (source.type) {
       data._ContentType = source.type;
     }
     const path = 'files/' + name;
-    return CoreManager.getRESTController().request('POST', path, data, options);
+    return CoreManager.getRESTController().request('POST', path, data, restOptions);
   },
 
-  download: function (uri, options) {
+  download: function (uri: string, options: any) {
     if (XHR) {
       return this.downloadAjax(uri, options);
     } else if (process.env.PARSE_BUILD === 'node') {
@@ -506,7 +513,7 @@ const DefaultController = {
     }
   },
 
-  downloadAjax: function (uri, options) {
+  downloadAjax: function (uri: string, options: any) {
     return new Promise((resolve, reject) => {
       const xhr = new XHR();
       xhr.open('GET', uri, true);
diff --git a/src/ParseGeoPoint.js b/src/ParseGeoPoint.ts
similarity index 98%
rename from src/ParseGeoPoint.js
rename to src/ParseGeoPoint.ts
index 3af089e98..66ec076fc 100644
--- a/src/ParseGeoPoint.js
+++ b/src/ParseGeoPoint.ts
@@ -102,7 +102,7 @@ class ParseGeoPoint {
     };
   }
 
-  equals(other: mixed): boolean {
+  equals(other: any): boolean {
     return (
       other instanceof ParseGeoPoint &&
       this.latitude === other.latitude &&
@@ -186,6 +186,7 @@ class ParseGeoPoint {
    * @static
    * @returns {Parse.GeoPoint} User's current location
    */
+  // TODO: Typescript; How does this thing work?
   static current() {
     return navigator.geolocation.getCurrentPosition(location => {
       return new ParseGeoPoint(location.coords.latitude, location.coords.longitude);
diff --git a/src/ParseHooks.js b/src/ParseHooks.ts
similarity index 73%
rename from src/ParseHooks.js
rename to src/ParseHooks.ts
index 8a5982687..8a8571a1f 100644
--- a/src/ParseHooks.js
+++ b/src/ParseHooks.ts
@@ -10,15 +10,15 @@ export function getTriggers() {
   return CoreManager.getHooksController().get('triggers');
 }
 
-export function getFunction(name) {
+export function getFunction(name: string) {
   return CoreManager.getHooksController().get('functions', name);
 }
 
-export function getTrigger(className, triggerName) {
+export function getTrigger(className: string, triggerName: string) {
   return CoreManager.getHooksController().get('triggers', className, triggerName);
 }
 
-export function createFunction(functionName, url) {
+export function createFunction(functionName: string, url: string) {
   return create({ functionName: functionName, url: url });
 }
 
@@ -34,7 +34,7 @@ export function updateFunction(functionName, url) {
   return update({ functionName: functionName, url: url });
 }
 
-export function updateTrigger(className, triggerName, url) {
+export function updateTrigger(className: string, triggerName: string, url: string) {
   return update({ className: className, triggerName: triggerName, url: url });
 }
 
@@ -54,8 +54,10 @@ export function remove(hook) {
   return CoreManager.getHooksController().remove(hook);
 }
 
+export type HookDeclaration = { functionName: string, url: string } | { className: string, triggerName: string, url: string };
+export type HookDeleteArg = { functionName: string } | { className: string, triggerName: string };
 const DefaultController = {
-  get(type, functionName, triggerName) {
+  get(type: string, functionName?: string, triggerName?: string) {
     let url = '/hooks/' + type;
     if (functionName) {
       url += '/' + functionName;
@@ -66,11 +68,11 @@ const DefaultController = {
     return this.sendRequest('GET', url);
   },
 
-  create(hook) {
-    let url;
-    if (hook.functionName && hook.url) {
+  create(hook: HookDeclaration) {
+    let url: string;
+    if ('functionName' in hook && hook.url) {
       url = '/hooks/functions';
-    } else if (hook.className && hook.triggerName && hook.url) {
+    } else if ('className' in hook && hook.triggerName && hook.url) {
       url = '/hooks/triggers';
     } else {
       return Promise.reject({ error: 'invalid hook declaration', code: 143 });
@@ -78,9 +80,9 @@ const DefaultController = {
     return this.sendRequest('POST', url, hook);
   },
 
-  remove(hook) {
-    let url;
-    if (hook.functionName) {
+  remove(hook: { functionName: string } | { className: string, triggerName: string }) {
+    let url: string;
+    if ('functionName' in hook) {
       url = '/hooks/functions/' + hook.functionName;
       delete hook.functionName;
     } else if (hook.className && hook.triggerName) {
@@ -93,12 +95,12 @@ const DefaultController = {
     return this.sendRequest('PUT', url, { __op: 'Delete' });
   },
 
-  update(hook) {
-    let url;
-    if (hook.functionName && hook.url) {
+  update(hook: HookDeclaration) {
+    let url: string;
+    if ('functionName' in hook && hook.url) {
       url = '/hooks/functions/' + hook.functionName;
       delete hook.functionName;
-    } else if (hook.className && hook.triggerName && hook.url) {
+    } else if ('className' in hook && hook.triggerName && hook.url) {
       url = '/hooks/triggers/' + hook.className + '/' + hook.triggerName;
       delete hook.className;
       delete hook.triggerName;
@@ -108,7 +110,7 @@ const DefaultController = {
     return this.sendRequest('PUT', url, hook);
   },
 
-  sendRequest(method, url, body) {
+  sendRequest(method: string, url: string, body?: any) {
     return CoreManager.getRESTController()
       .request(method, url, body, { useMasterKey: true })
       .then(res => {
diff --git a/src/ParseObject.js b/src/ParseObject.ts
similarity index 93%
rename from src/ParseObject.js
rename to src/ParseObject.ts
index 32701191b..726fa3201 100644
--- a/src/ParseObject.js
+++ b/src/ParseObject.ts
@@ -36,12 +36,13 @@ import unsavedChildren from './unsavedChildren';
 import type { AttributeMap, OpsMap } from './ObjectStateMutations';
 import type { RequestOptions, FullOptions } from './RESTController';
 
-const uuidv4 = require('./uuid');
+import uuidv4 from './uuid';
 
 export type Pointer = {
   __type: string,
   className: string,
-  objectId: string,
+  objectId?: string,
+  _localId?: string
 };
 
 type SaveParams = {
@@ -53,6 +54,7 @@ type SaveParams = {
 export type SaveOptions = FullOptions & {
   cascadeSave?: boolean,
   context?: AttributeMap,
+  batchSize?: number
 };
 
 // Mapping of class names to constructors, so we can populate objects from the
@@ -80,6 +82,10 @@ function getServerUrlPath() {
   return url.substr(url.indexOf('/'));
 }
 
+type ObjectFetchOptions = {
+  useMasterKey?: boolean, sessionToken?: string, include?: string | string[], context?: AttributeMap,
+}
+
 /**
  * Creates a new model with defined attributes.
  *
@@ -105,8 +111,8 @@ class ParseObject {
    * @param {object} options The options for this object instance.
    */
   constructor(
-    className: ?string | { className: string, [attr: string]: mixed },
-    attributes?: { [attr: string]: mixed },
+    className?: string | { className: string, [attr: string]: any },
+    attributes?: { [attr: string]: any },
     options?: { ignoreValidation: boolean }
   ) {
     // Enable legacy initializers
@@ -114,7 +120,7 @@ class ParseObject {
       this.initialize.apply(this, arguments);
     }
 
-    let toSet = null;
+    let toSet: { [attr: string]: any } | null = null;
     this._objCount = objectCount++;
     if (typeof className === 'string') {
       this.className = className;
@@ -130,7 +136,7 @@ class ParseObject {
         }
       }
       if (attributes && typeof attributes === 'object') {
-        options = attributes;
+        options = attributes as any;
       }
     }
     if (toSet && !this.set(toSet, options)) {
@@ -143,8 +149,8 @@ class ParseObject {
    *
    * @property {string} id
    */
-  id: ?string;
-  _localId: ?string;
+  id?: string;
+  _localId?: string;
   _objCount: number;
   className: string;
 
@@ -161,7 +167,7 @@ class ParseObject {
    * @property {Date} createdAt
    * @returns {Date}
    */
-  get createdAt(): ?Date {
+  get createdAt(): Date | undefined {
     return this._getServerData().createdAt;
   }
 
@@ -171,7 +177,7 @@ class ParseObject {
    * @property {Date} updatedAt
    * @returns {Date}
    */
-  get updatedAt(): ?Date {
+  get updatedAt(): Date | undefined {
     return this._getServerData().updatedAt;
   }
 
@@ -280,7 +286,7 @@ class ParseObject {
   }
 
   _toFullJSON(seen?: Array, offline?: boolean): AttributeMap {
-    const json: { [key: string]: mixed } = this.toJSON(seen, offline);
+    const json: { [key: string]: any } = this.toJSON(seen, offline);
     json.__type = 'Object';
     json.className = this.className;
     return json;
@@ -290,7 +296,7 @@ class ParseObject {
     const pending = this._getPendingOps();
     const dirtyObjects = this._getDirtyObjectAttributes();
     const json = {};
-    let attr;
+    let attr: string;
 
     for (attr in dirtyObjects) {
       let isDotNotation = false;
@@ -346,7 +352,12 @@ class ParseObject {
     }
     const stateController = CoreManager.getObjectStateController();
     stateController.initializeState(this._getStateIdentifier());
-    const decoded = {};
+    const decoded: Partial<{
+      createdAt?: Date,
+      updatedAt?: Date,
+      ACL?: any // TODO: Maybe type this better?
+      [key: string]: any
+    }> = {};
     for (const attr in serverData) {
       if (attr === 'ACL') {
         decoded[attr] = new ParseACL(serverData[attr]);
@@ -395,7 +406,11 @@ class ParseObject {
   }
 
   _handleSaveResponse(response: AttributeMap, status: number) {
-    const changes = {};
+    const changes: Partial<{
+      createdAt: string,
+      updatedAt: string,
+      [key: string]: any
+    }> = {};
     let attr;
     const stateController = CoreManager.getObjectStateController();
     const pending = stateController.popPendingState(this._getStateIdentifier());
@@ -462,7 +477,7 @@ class ParseObject {
   toJSON(seen: Array | void, offline?: boolean): AttributeMap {
     const seenEntry = this.id ? this.className + ':' + this.id : this;
     seen = seen || [seenEntry];
-    const json = {};
+    const json: AttributeMap = {};
     const attrs = this.attributes;
     for (const attr in attrs) {
       if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) {
@@ -488,7 +503,7 @@ class ParseObject {
    * @param {object} other - An other object ot compare
    * @returns {boolean}
    */
-  equals(other: mixed): boolean {
+  equals(other: any): boolean {
     if (this === other) {
       return true;
     }
@@ -602,7 +617,7 @@ class ParseObject {
    * @param {string} attr The string name of an attribute.
    * @returns {*}
    */
-  get(attr: string): mixed {
+  get(attr: string): any {
     return this.attributes[attr];
   }
 
@@ -689,22 +704,24 @@ class ParseObject {
    *     The only supported option is error.
    * @returns {(ParseObject|boolean)} true if the set succeeded.
    */
-  set(key: mixed, value: mixed, options?: mixed): ParseObject | boolean {
-    let changes = {};
+  set(keyOrAttributes: string | AttributeMap, valueOrOptions?: any, options?: any): ParseObject | boolean {
+    let changes: AttributeMap = {};
     const newOps = {};
-    if (key && typeof key === 'object') {
-      changes = key;
-      options = value;
+    let key: string;
+    if (keyOrAttributes && typeof keyOrAttributes === 'object') {
+      changes = keyOrAttributes;
+      options = valueOrOptions;
     } else if (typeof key === 'string') {
-      changes[key] = value;
+      changes[key] = valueOrOptions;
     } else {
+      // Key is weird; just return ourself
       return this;
     }
 
     options = options || {};
     let readonly = [];
-    if (typeof this.constructor.readOnlyAttributes === 'function') {
-      readonly = readonly.concat(this.constructor.readOnlyAttributes());
+    if (typeof ((this.constructor as any).readOnlyAttributes) === 'function') {
+      readonly = readonly.concat((this.constructor as any).readOnlyAttributes());
     }
     for (const k in changes) {
       if (k === 'createdAt' || k === 'updatedAt') {
@@ -787,7 +804,7 @@ class ParseObject {
    * @param options
    * @returns {(ParseObject | boolean)}
    */
-  unset(attr: string, options?: { [opt: string]: mixed }): ParseObject | boolean {
+  unset(attr: string, options?: { [opt: string]: any }): ParseObject | boolean {
     options = options || {};
     options.unset = true;
     return this.set(attr, null, options);
@@ -837,7 +854,7 @@ class ParseObject {
    * @param item {} The item to add.
    * @returns {(ParseObject | boolean)}
    */
-  add(attr: string, item: mixed): ParseObject | boolean {
+  add(attr: string, item: any): ParseObject | boolean {
     return this.set(attr, new AddOp([item]));
   }
 
@@ -849,7 +866,7 @@ class ParseObject {
    * @param items {Object[]} The items to add.
    * @returns {(ParseObject | boolean)}
    */
-  addAll(attr: string, items: Array): ParseObject | boolean {
+  addAll(attr: string, items: Array): ParseObject | boolean {
     return this.set(attr, new AddOp(items));
   }
 
@@ -862,7 +879,7 @@ class ParseObject {
    * @param item {} The object to add.
    * @returns {(ParseObject | boolean)}
    */
-  addUnique(attr: string, item: mixed): ParseObject | boolean {
+  addUnique(attr: string, item: any): ParseObject | boolean {
     return this.set(attr, new AddUniqueOp([item]));
   }
 
@@ -875,7 +892,7 @@ class ParseObject {
    * @param items {Object[]} The objects to add.
    * @returns {(ParseObject | boolean)}
    */
-  addAllUnique(attr: string, items: Array): ParseObject | boolean {
+  addAllUnique(attr: string, items: Array): ParseObject | boolean {
     return this.set(attr, new AddUniqueOp(items));
   }
 
@@ -887,7 +904,7 @@ class ParseObject {
    * @param item {} The object to remove.
    * @returns {(ParseObject | boolean)}
    */
-  remove(attr: string, item: mixed): ParseObject | boolean {
+  remove(attr: string, item: any): ParseObject | boolean {
     return this.set(attr, new RemoveOp([item]));
   }
 
@@ -899,7 +916,7 @@ class ParseObject {
    * @param items {Object[]} The object to remove.
    * @returns {(ParseObject | boolean)}
    */
-  removeAll(attr: string, items: Array): ParseObject | boolean {
+  removeAll(attr: string, items: Array): ParseObject | boolean {
     return this.set(attr, new RemoveOp(items));
   }
 
@@ -912,7 +929,7 @@ class ParseObject {
    * @param attr {String} The key.
    * @returns {Parse.Op | undefined} The operation, or undefined if none.
    */
-  op(attr: string): ?Op {
+  op(attr: string): Op | undefined {
     const pending = this._getPendingOps();
     for (let i = pending.length; i--;) {
       if (pending[i][attr]) {
@@ -926,11 +943,11 @@ class ParseObject {
    *
    * @returns {Parse.Object}
    */
-  clone(): any {
-    const clone = new this.constructor(this.className);
+  clone(): typeof this {
+    const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className);
     let attributes = this.attributes;
-    if (typeof this.constructor.readOnlyAttributes === 'function') {
-      const readonly = this.constructor.readOnlyAttributes() || [];
+    if (typeof (this.constructor as any).readOnlyAttributes === 'function') {
+      const readonly = (this.constructor as any).readOnlyAttributes() || [];
       // Attributes are frozen, so we have to rebuild an object,
       // rather than delete readonly keys
       const copy = {};
@@ -953,7 +970,7 @@ class ParseObject {
    * @returns {Parse.Object}
    */
   newInstance(): any {
-    const clone = new this.constructor(this.className);
+    const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className);
     clone.id = this.id;
     if (singleInstance) {
       // Just return an object with the right id
@@ -1060,7 +1077,7 @@ class ParseObject {
    * @returns {Parse.ACL|null} An instance of Parse.ACL.
    * @see Parse.Object#get
    */
-  getACL(): ?ParseACL {
+  getACL(): ParseACL | null {
     const acl = this.get('ACL');
     if (acl instanceof ParseACL) {
       return acl;
@@ -1076,7 +1093,7 @@ class ParseObject {
    * @returns {(ParseObject | boolean)} Whether the set passed validation.
    * @see Parse.Object#set
    */
-  setACL(acl: ParseACL, options?: mixed): ParseObject | boolean {
+  setACL(acl: ParseACL, options?: any): ParseObject | boolean {
     return this.set('ACL', acl, options);
   }
 
@@ -1109,8 +1126,8 @@ class ParseObject {
     const attributes = this.attributes;
     const erasable = {};
     let readonly = ['createdAt', 'updatedAt'];
-    if (typeof this.constructor.readOnlyAttributes === 'function') {
-      readonly = readonly.concat(this.constructor.readOnlyAttributes());
+    if (typeof (this.constructor as any).readOnlyAttributes === 'function') {
+      readonly = readonly.concat((this.constructor as any).readOnlyAttributes());
     }
     for (const attr in attributes) {
       if (readonly.indexOf(attr) < 0) {
@@ -1137,9 +1154,9 @@ class ParseObject {
    * @returns {Promise} A promise that is fulfilled when the fetch
    *     completes.
    */
-  fetch(options: RequestOptions): Promise {
+  fetch(options: ObjectFetchOptions): Promise {
     options = options || {};
-    const fetchOptions = {};
+    const fetchOptions: ObjectFetchOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       fetchOptions.useMasterKey = options.useMasterKey;
     }
@@ -1156,7 +1173,7 @@ class ParseObject {
           if (Array.isArray(key)) {
             fetchOptions.include = fetchOptions.include.concat(key);
           } else {
-            fetchOptions.include.push(key);
+            (fetchOptions.include as string[]).push(key);
           }
         });
       } else {
@@ -1185,7 +1202,7 @@ class ParseObject {
    * @returns {Promise} A promise that is fulfilled when the fetch
    *     completes.
    */
-  fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise {
+  fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise {
     options = options || {};
     options.include = keys;
     return this.fetch(options);
@@ -1215,7 +1232,7 @@ class ParseObject {
    * @returns {Promise} A promise that is fulfilled when the save
    * completes.
    */
-  async saveEventually(options: SaveOptions): Promise {
+  async saveEventually(options: SaveOptions): Promise {
     try {
       await this.save(null, options);
     } catch (e) {
@@ -1291,12 +1308,12 @@ class ParseObject {
    * completes.
    */
   save(
-    arg1: ?string | { [attr: string]: mixed },
-    arg2: SaveOptions | mixed,
+    arg1: undefined | string | { [attr: string]: any },
+    arg2: SaveOptions | any,
     arg3?: SaveOptions
-  ): Promise {
-    let attrs;
-    let options;
+  ): Promise {
+    let attrs: { [attr: string]: any };
+    let options: SaveOptions;
     if (typeof arg1 === 'object' || typeof arg1 === 'undefined') {
       attrs = arg1;
       if (typeof arg2 === 'object') {
@@ -1317,7 +1334,7 @@ class ParseObject {
     }
 
     options = options || {};
-    const saveOptions = {};
+    const saveOptions: SaveOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       saveOptions.useMasterKey = !!options.useMasterKey;
     }
@@ -1334,7 +1351,7 @@ class ParseObject {
     const unsaved = options.cascadeSave !== false ? unsavedChildren(this) : null;
     return controller.save(unsaved, saveOptions).then(() => {
       return controller.save(this, saveOptions);
-    });
+    }) as Promise as Promise;
   }
 
   /**
@@ -1359,7 +1376,7 @@ class ParseObject {
    * @returns {Promise} A promise that is fulfilled when the destroy
    *     completes.
    */
-  async destroyEventually(options: RequestOptions): Promise {
+  async destroyEventually(options: RequestOptions): Promise {
     try {
       await this.destroy(options);
     } catch (e) {
@@ -1385,9 +1402,9 @@ class ParseObject {
    * @returns {Promise} A promise that is fulfilled when the destroy
    *     completes.
    */
-  destroy(options: RequestOptions): Promise {
+  destroy(options: RequestOptions): Promise {
     options = options || {};
-    const destroyOptions = {};
+    const destroyOptions: RequestOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       destroyOptions.useMasterKey = options.useMasterKey;
     }
@@ -1400,7 +1417,7 @@ class ParseObject {
     if (!this.id) {
       return Promise.resolve();
     }
-    return CoreManager.getObjectController().destroy(this, destroyOptions);
+    return CoreManager.getObjectController().destroy(this, destroyOptions) as Promise;
   }
 
   /**
@@ -1552,7 +1569,7 @@ class ParseObject {
    * @returns {Parse.Object[]}
    */
   static fetchAll(list: Array, options: RequestOptions = {}) {
-    const queryOptions = {};
+    const queryOptions: RequestOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       queryOptions.useMasterKey = options.useMasterKey;
     }
@@ -1662,10 +1679,8 @@ class ParseObject {
    * @static
    * @returns {Parse.Object[]}
    */
-  static fetchAllIfNeeded(list: Array, options) {
-    options = options || {};
-
-    const queryOptions = {};
+  static fetchAllIfNeeded(list: Array, options: ObjectFetchOptions = {}) {
+    const queryOptions: ObjectFetchOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       queryOptions.useMasterKey = options.useMasterKey;
     }
@@ -1740,8 +1755,8 @@ class ParseObject {
    * @returns {Promise} A promise that is fulfilled when the destroyAll
    * completes.
    */
-  static destroyAll(list: Array, options = {}) {
-    const destroyOptions = {};
+  static destroyAll(list: Array, options: SaveOptions = {}) {
+    const destroyOptions: SaveOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       destroyOptions.useMasterKey = options.useMasterKey;
     }
@@ -1775,8 +1790,8 @@ class ParseObject {
    * @static
    * @returns {Parse.Object[]}
    */
-  static saveAll(list: Array, options: RequestOptions = {}) {
-    const saveOptions = {};
+  static saveAll(list: Array, options: SaveOptions = {}) {
+    const saveOptions: SaveOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       saveOptions.useMasterKey = options.useMasterKey;
     }
@@ -1806,7 +1821,7 @@ class ParseObject {
    * @static
    * @returns {Parse.Object} A Parse.Object reference.
    */
-  static createWithoutData(id: string) {
+  static createWithoutData(id: string): ParseObject {
     const obj = new this();
     obj.id = id;
     return obj;
@@ -1822,13 +1837,13 @@ class ParseObject {
    * @static
    * @returns {Parse.Object} A Parse.Object reference
    */
-  static fromJSON(json: any, override?: boolean, dirty?: boolean) {
+  static fromJSON(json: any, override?: boolean, dirty?: boolean): ParseObject {
     if (!json.className) {
       throw new Error('Cannot create an object without a className');
     }
     const constructor = classMap[json.className];
     const o = constructor ? new constructor(json.className) : new ParseObject(json.className);
-    const otherAttributes = {};
+    const otherAttributes: AttributeMap = {};
     for (const attr in json) {
       if (attr !== 'className' && attr !== '__type') {
         otherAttributes[attr] = json[attr];
@@ -1877,7 +1892,7 @@ class ParseObject {
     if (typeof constructor !== 'function') {
       throw new TypeError(
         'You must register the subclass constructor. ' +
-          'Did you attempt to register an instance of the subclass?'
+        'Did you attempt to register an instance of the subclass?'
       );
     }
     classMap[className] = constructor;
@@ -1950,7 +1965,7 @@ class ParseObject {
     }
 
     let parentProto = ParseObject.prototype;
-    if (this.hasOwnProperty('__super__') && this.__super__) {
+    if (this.hasOwnProperty('__super__') && (this as any).__super__) {
       parentProto = this.prototype;
     }
     let ParseObjectSubclass = function (attributes, options) {
@@ -1976,15 +1991,16 @@ class ParseObject {
     if (classMap[adjustedClassName]) {
       ParseObjectSubclass = classMap[adjustedClassName];
     } else {
-      ParseObjectSubclass.extend = function (name, protoProps, classProps) {
+      // TODO: Maybe there is a more elegant solution to this?
+      (ParseObjectSubclass as any).extend = function (name: string, protoProps: any, classProps: any) {
         if (typeof name === 'string') {
           return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps);
         }
         return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps);
       };
-      ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData;
-      ParseObjectSubclass.className = adjustedClassName;
-      ParseObjectSubclass.__super__ = parentProto;
+      (ParseObjectSubclass as any).createWithoutData = ParseObject.createWithoutData;
+      (ParseObjectSubclass as any).className = adjustedClassName;
+      (ParseObjectSubclass as any).__super__ = parentProto;
       ParseObjectSubclass.prototype = Object.create(parentProto, {
         constructor: {
           value: ParseObjectSubclass,
@@ -2195,16 +2211,18 @@ const DefaultController = {
     target: ParseObject | Array,
     forceFetch: boolean,
     options: RequestOptions
-  ): Promise | ParseObject> {
+  ): Promise | ParseObject | undefined> {
     const localDatastore = CoreManager.getLocalDatastore();
     if (Array.isArray(target)) {
       if (target.length < 1) {
         return Promise.resolve([]);
       }
-      const objs = [];
-      const ids = [];
-      let className = null;
-      const results = [];
+      /** Resulting Parse.Objects that have data */
+      const objs: ParseObject[] = [];
+      /** IDs to fetch */
+      const ids: string[] = [];
+      let className: null | string = null;
+      const results: ParseObject[] = [];
       let error = null;
       target.forEach(el => {
         if (error) {
@@ -2231,14 +2249,15 @@ const DefaultController = {
       if (error) {
         return Promise.reject(error);
       }
+      // Construct a ParseQuery that finds objects with matching IDs
       const query = new ParseQuery(className);
       query.containedIn('objectId', ids);
       if (options && options.include) {
         query.include(options.include);
       }
       query._limit = ids.length;
-      return query.find(options).then(async objects => {
-        const idMap = {};
+      return query.find(options).then(async (objects: ParseObject[]) => {
+        const idMap: Record = {};
         objects.forEach(o => {
           idMap[o.id] = o;
         });
@@ -2253,7 +2272,7 @@ const DefaultController = {
           }
         }
         if (!singleInstance) {
-          // If single instance objects are disabled, we need to replace the
+          // If single instance objects are disabled, we need to replace the objects in the results array.
           for (let i = 0; i < results.length; i++) {
             const obj = results[i];
             if (obj && obj.id && idMap[obj.id]) {
@@ -2275,7 +2294,7 @@ const DefaultController = {
         );
       }
       const RESTController = CoreManager.getRESTController();
-      const params = {};
+      const params: RequestOptions = {};
       if (options && options.include) {
         params.include = options.include.join();
       }
@@ -2292,13 +2311,14 @@ const DefaultController = {
         return target;
       });
     }
-    return Promise.resolve();
+    // Not Array, and not ParseObject; return undefined/void.
+    return Promise.resolve(undefined);
   },
 
   async destroy(
     target: ParseObject | Array,
-    options: RequestOptions
-  ): Promise | ParseObject> {
+    options: SaveOptions
+  ): Promise | ParseObject> {
     const batchSize =
       options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE');
     const localDatastore = CoreManager.getLocalDatastore();
@@ -2308,7 +2328,7 @@ const DefaultController = {
       if (target.length < 1) {
         return Promise.resolve([]);
       }
-      const batches = [[]];
+      const batches: ParseObject[][] = [[]];
       target.forEach(obj => {
         if (!obj.id) {
           return;
@@ -2400,7 +2420,7 @@ const DefaultController = {
       }
       unsaved = unique(unsaved);
 
-      const filesSaved: Array = [];
+      const filesSaved: Array> = [];
       let pending: Array = [];
       unsaved.forEach(el => {
         if (el instanceof ParseFile) {
diff --git a/src/ParseOp.js b/src/ParseOp.ts
similarity index 76%
rename from src/ParseOp.js
rename to src/ParseOp.ts
index a35485c60..5da8cde7f 100644
--- a/src/ParseOp.js
+++ b/src/ParseOp.ts
@@ -5,71 +5,73 @@
 import arrayContainsObject from './arrayContainsObject';
 import decode from './decode';
 import encode from './encode';
-import ParseObject from './ParseObject';
+import ParseObject, { Pointer } from './ParseObject';
 import ParseRelation from './ParseRelation';
 import unique from './unique';
 
-export function opFromJSON(json: { [key: string]: any }): ?Op {
+export function opFromJSON(json: { [key: string]: any }): Op | null {
   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': {
-    const toAdd = decode(json.objects);
-    if (!Array.isArray(toAdd)) {
-      return new RelationOp([], []);
-    }
-    return new RelationOp(toAdd, []);
-  }
-  case 'RemoveRelation': {
-    const toRemove = decode(json.objects);
-    if (!Array.isArray(toRemove)) {
-      return new RelationOp([], []);
+    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': {
+      const toAdd = decode(json.objects);
+      if (!Array.isArray(toAdd)) {
+        return new RelationOp([], []);
+      }
+      return new RelationOp(toAdd, []);
     }
-    return new RelationOp([], toRemove);
-  }
-  case 'Batch': {
-    let toAdd = [];
-    let toRemove = [];
-    for (let 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));
+    case 'RemoveRelation': {
+      const toRemove = decode(json.objects);
+      if (!Array.isArray(toRemove)) {
+        return new RelationOp([], []);
       }
+      return new RelationOp([], toRemove);
+    }
+    case 'Batch': {
+      let toAdd = [];
+      let toRemove = [];
+      for (let 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 new RelationOp(toAdd, toRemove);
-  }
   }
   return null;
 }
 
 export class Op {
+  __op?: string;
+  objects?: any[];
   // Empty parent class
-  applyTo(value: mixed): mixed {} /* eslint-disable-line no-unused-vars */
-  mergeWith(previous: Op): ?Op {} /* eslint-disable-line no-unused-vars */
-  toJSON(): mixed {}
+  applyTo(...value: any): any { } /* eslint-disable-line no-unused-vars */
+  mergeWith(previous: Op): Op | void { } /* eslint-disable-line no-unused-vars */
+  toJSON(offline?: boolean): any { }
 }
 
 export class SetOp extends Op {
-  _value: ?mixed;
+  _value: any;
 
-  constructor(value: mixed) {
+  constructor(value: any) {
     super();
     this._value = value;
   }
 
-  applyTo(): mixed {
+  applyTo(): any {
     return this._value;
   }
 
@@ -77,7 +79,7 @@ export class SetOp extends Op {
     return new SetOp(this._value);
   }
 
-  toJSON(offline?: boolean) {
+  toJSON(offline?: boolean) : any {
     return encode(this._value, false, true, undefined, offline);
   }
 }
@@ -107,7 +109,7 @@ export class IncrementOp extends Op {
     this._amount = amount;
   }
 
-  applyTo(value: ?mixed): number {
+  applyTo(value: any): number {
     if (typeof value === 'undefined') {
       return this._amount;
     }
@@ -139,14 +141,14 @@ export class IncrementOp extends Op {
 }
 
 export class AddOp extends Op {
-  _value: Array;
+  _value: Array;
 
-  constructor(value: mixed | Array) {
+  constructor(value: any | Array) {
     super();
     this._value = Array.isArray(value) ? value : [value];
   }
 
-  applyTo(value: mixed): Array {
+  applyTo(value: any): Array {
     if (value == null) {
       return this._value;
     }
@@ -172,25 +174,25 @@ export class AddOp extends Op {
     throw new Error('Cannot merge Add Op with the previous Op');
   }
 
-  toJSON(): { __op: string, objects: mixed } {
+  toJSON(): { __op: string, objects: any } {
     return { __op: 'Add', objects: encode(this._value, false, true) };
   }
 }
 
 export class AddUniqueOp extends Op {
-  _value: Array;
+  _value: Array;
 
-  constructor(value: mixed | Array) {
+  constructor(value: any | Array) {
     super();
     this._value = unique(Array.isArray(value) ? value : [value]);
   }
 
-  applyTo(value: mixed | Array): Array {
+  applyTo(value: any | Array): Array {
     if (value == null) {
       return this._value || [];
     }
     if (Array.isArray(value)) {
-      const toAdd = [];
+      const toAdd: any[] = [];
       this._value.forEach(v => {
         if (v instanceof ParseObject) {
           if (!arrayContainsObject(value, v)) {
@@ -223,20 +225,20 @@ export class AddUniqueOp extends Op {
     throw new Error('Cannot merge AddUnique Op with the previous Op');
   }
 
-  toJSON(): { __op: string, objects: mixed } {
+  toJSON(): { __op: string, objects: any } {
     return { __op: 'AddUnique', objects: encode(this._value, false, true) };
   }
 }
 
 export class RemoveOp extends Op {
-  _value: Array;
+  _value: Array;
 
-  constructor(value: mixed | Array) {
+  constructor(value: any | Array) {
     super();
     this._value = unique(Array.isArray(value) ? value : [value]);
   }
 
-  applyTo(value: mixed | Array): Array {
+  applyTo(value: any | Array): Array {
     if (value == null) {
       return [];
     }
@@ -291,13 +293,13 @@ export class RemoveOp extends Op {
     throw new Error('Cannot merge Remove Op with the previous Op');
   }
 
-  toJSON(): { __op: string, objects: mixed } {
+  toJSON(): { __op: string, objects: any } {
     return { __op: 'Remove', objects: encode(this._value, false, true) };
   }
 }
 
 export class RelationOp extends Op {
-  _targetClassName: ?string;
+  _targetClassName: string | null;
   relationsToAdd: Array;
   relationsToRemove: Array;
 
@@ -327,16 +329,16 @@ export class RelationOp extends Op {
     if (this._targetClassName !== obj.className) {
       throw new Error(
         'Tried to create a Relation with 2 different object types: ' +
-          this._targetClassName +
-          ' and ' +
-          obj.className +
-          '.'
+        this._targetClassName +
+        ' and ' +
+        obj.className +
+        '.'
       );
     }
     return obj.id;
   }
 
-  applyTo(value: mixed, object?: { className: string, id: ?string }, key?: string): ?ParseRelation {
+  applyTo(value: any, object?: { className: string, id?: string }, key?: string): ParseRelation {
     if (!value) {
       if (!object || !key) {
         throw new Error(
@@ -359,10 +361,10 @@ export class RelationOp extends Op {
           if (this._targetClassName !== value.targetClassName) {
             throw new Error(
               'Related object must be a ' +
-                value.targetClassName +
-                ', but a ' +
-                this._targetClassName +
-                ' was passed in.'
+              value.targetClassName +
+              ', but a ' +
+              this._targetClassName +
+              ' was passed in.'
             );
           }
         } else {
@@ -386,10 +388,10 @@ export class RelationOp extends Op {
       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.'
+          previous._targetClassName +
+          ', but ' +
+          (this._targetClassName || 'null') +
+          ' was passed in.'
         );
       }
       const newAdd = previous.relationsToAdd.concat([]);
@@ -427,18 +429,19 @@ export class RelationOp extends Op {
     throw new Error('Cannot merge Relation Op with the previous Op');
   }
 
-  toJSON(): { __op?: string, objects?: mixed, ops?: mixed } {
-    const idToPointer = id => {
-      return {
+  toJSON(): { __op?: string, objects?: any, ops?: any } {
+    const idToPointer = (id: string) => {
+      const ret: Pointer = {
         __type: 'Pointer',
-        className: this._targetClassName,
+        className: this._targetClassName!,
         objectId: id,
       };
+      return ret;
     };
 
-    let adds = null;
-    let removes = null;
-    let pointers = null;
+    let pointers: null | (Pointer[]) = null;
+    let adds: null | { __op: string, objects: null | (Pointer[]) } = null;
+    let removes: null | { __op: string, objects: null | (Pointer[]) } = null;
 
     if (this.relationsToAdd.length > 0) {
       pointers = this.relationsToAdd.map(idToPointer);
@@ -452,7 +455,6 @@ export class RelationOp extends Op {
     if (adds && removes) {
       return { __op: 'Batch', ops: [adds, removes] };
     }
-
     return adds || removes || {};
   }
 }
diff --git a/src/ParseRelation.js b/src/ParseRelation.ts
similarity index 95%
rename from src/ParseRelation.js
rename to src/ParseRelation.ts
index 50c8c09f1..1633d3f96 100644
--- a/src/ParseRelation.js
+++ b/src/ParseRelation.ts
@@ -20,15 +20,15 @@ import ParseQuery from './ParseQuery';
  * @alias Parse.Relation
  */
 class ParseRelation {
-  parent: ?ParseObject;
-  key: ?string;
-  targetClassName: ?string;
+  parent?: ParseObject;
+  key?: string;
+  targetClassName: string | null;
 
   /**
    * @param {Parse.Object} parent The parent of this relation.
    * @param {string} key The key for this relation on the parent.
    */
-  constructor(parent: ?ParseObject, key: ?string) {
+  constructor(parent?: ParseObject, key?: string) {
     this.parent = parent;
     this.key = key;
     this.targetClassName = null;
@@ -108,7 +108,7 @@ class ParseRelation {
    *
    * @returns {object} JSON representation of Relation
    */
-  toJSON(): { __type: 'Relation', className: ?string } {
+  toJSON(): { __type: 'Relation', className: string | null } {
     return {
       __type: 'Relation',
       className: this.targetClassName,
diff --git a/src/ParseRole.js b/src/ParseRole.ts
similarity index 94%
rename from src/ParseRole.js
rename to src/ParseRole.ts
index fee282395..48c28f52b 100644
--- a/src/ParseRole.js
+++ b/src/ParseRole.ts
@@ -42,7 +42,7 @@ class ParseRole extends ParseObject {
    *
    * @returns {string} the name of the role.
    */
-  getName(): ?string {
+  getName(): string | null | undefined {
     const name = this.get('name');
     if (name == null || typeof name === 'string') {
       return name;
@@ -67,7 +67,7 @@ class ParseRole extends ParseObject {
    *     callbacks.
    * @returns {(ParseObject|boolean)} true if the set succeeded.
    */
-  setName(name: string, options?: mixed): ParseObject | boolean {
+  setName(name: string, options?: any): ParseObject | boolean {
     this._validateName(name);
     return this.set('name', name, options);
   }
@@ -114,8 +114,8 @@ class ParseRole extends ParseObject {
     }
   }
 
-  validate(attrs: AttributeMap, options?: mixed): ParseError | boolean {
-    const isInvalid = super.validate(attrs, options);
+  validate(attrs: AttributeMap, options?: any): ParseError | boolean {
+    const isInvalid = (super.validate as typeof this['validate'])(attrs, options);
     if (isInvalid) {
       return isInvalid;
     }
diff --git a/src/ParseSchema.js b/src/ParseSchema.ts
similarity index 93%
rename from src/ParseSchema.js
rename to src/ParseSchema.ts
index 089cddd32..8a1e16a8b 100644
--- a/src/ParseSchema.js
+++ b/src/ParseSchema.ts
@@ -21,11 +21,13 @@ const FIELD_TYPES = [
   'Object',
   'Pointer',
   'Relation',
-];
+] as const;
 
+type ValidFieldType = typeof FIELD_TYPES[number];
 type FieldOptions = {
-  required: boolean,
-  defaultValue: mixed,
+  required?: boolean,
+  defaultValue?: any,
+  targetClass?: string,
 };
 
 /**
@@ -47,9 +49,9 @@ type FieldOptions = {
  */
 class ParseSchema {
   className: string;
-  _fields: { [key: string]: mixed };
-  _indexes: { [key: string]: mixed };
-  _clp: { [key: string]: mixed };
+  _fields: { [key: string]: any };
+  _indexes: { [key: string]: any };
+  _clp: { [key: string]: any };
 
   /**
    * @param {string} className Parse Class string.
@@ -212,7 +214,7 @@ class ParseSchema {
    * 
    * @returns {Parse.Schema} Returns the schema, so you can chain this call.
    */
-  addField(name: string, type: string, options: FieldOptions = {}) {
+  addField(name: string, type: ValidFieldType, options: FieldOptions = {}) {
     type = type || 'String';
 
     if (!name) {
@@ -222,12 +224,15 @@ class ParseSchema {
       throw new Error(`${type} is not a valid type.`);
     }
     if (type === 'Pointer') {
-      return this.addPointer(name, options.targetClass, options);
+      return this.addPointer(name, options.targetClass!, options);
     }
     if (type === 'Relation') {
+      // TODO: Why does options exist here?
       return this.addRelation(name, options.targetClass, options);
     }
-    const fieldOptions = { type };
+    const fieldOptions: Partial & {
+      type: ValidFieldType,
+    } = { type };
 
     if (typeof options.required === 'boolean') {
       fieldOptions.required = options.required;
@@ -404,7 +409,9 @@ class ParseSchema {
     if (!targetClass) {
       throw new Error('You need to set the targetClass of the Pointer.');
     }
-    const fieldOptions = { type: 'Pointer', targetClass };
+    const fieldOptions: Partial & {
+      type: ValidFieldType,
+    } = { type: 'Pointer', targetClass };
 
     if (typeof options.required === 'boolean') {
       fieldOptions.required = options.required;
@@ -466,30 +473,30 @@ class ParseSchema {
 }
 
 const DefaultController = {
-  send(className: string, method: string, params: any = {}): Promise {
+  send(className: string, method: string, params: any = {}): Promise {
     const RESTController = CoreManager.getRESTController();
     return RESTController.request(method, `schemas/${className}`, params, {
       useMasterKey: true,
     });
   },
 
-  get(className: string): Promise {
+  get(className: string): Promise {
     return this.send(className, 'GET');
   },
 
-  create(className: string, params: any): Promise {
+  create(className: string, params: any): Promise {
     return this.send(className, 'POST', params);
   },
 
-  update(className: string, params: any): Promise {
+  update(className: string, params: any): Promise {
     return this.send(className, 'PUT', params);
   },
 
-  delete(className: string): Promise {
+  delete(className: string): Promise {
     return this.send(className, 'DELETE');
   },
 
-  purge(className: string): Promise {
+  purge(className: string): Promise {
     const RESTController = CoreManager.getRESTController();
     return RESTController.request('DELETE', `purge/${className}`, {}, { useMasterKey: true });
   },
diff --git a/src/ParseSession.ts b/src/ParseSession.ts
index 51b001742..cfb678373 100644
--- a/src/ParseSession.ts
+++ b/src/ParseSession.ts
@@ -57,7 +57,7 @@ class ParseSession extends ParseObject {
     options = options || {};
     const controller = CoreManager.getSessionController();
 
-    const sessionOptions = {};
+    const sessionOptions : FullOptions = {};
     if (options.hasOwnProperty('useMasterKey')) {
       sessionOptions.useMasterKey = options.useMasterKey;
     }
diff --git a/src/RESTController.js b/src/RESTController.ts
similarity index 93%
rename from src/RESTController.js
rename to src/RESTController.ts
index 75b30a759..b4758f4b5 100644
--- a/src/RESTController.js
+++ b/src/RESTController.ts
@@ -2,7 +2,7 @@
  * @flow
  */
 /* global XMLHttpRequest, XDomainRequest */
-const uuidv4 = require('./uuid');
+import uuidv4 from './uuid';
 
 import CoreManager from './CoreManager';
 import ParseError from './ParseError';
@@ -28,9 +28,10 @@ export type FullOptions = {
   installationId?: string,
   progress?: any,
   usePost?: boolean,
+  requestTask?: any,
 };
 
-let XHR = null;
+let XHR: typeof XMLHttpRequest = null;
 if (typeof XMLHttpRequest !== 'undefined') {
   XHR = XMLHttpRequest;
 }
@@ -42,12 +43,14 @@ if (process.env.PARSE_BUILD === 'weapp') {
 }
 
 let useXDomainRequest = false;
+// @ts-ignore
 if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) {
   useXDomainRequest = true;
 }
 
 function ajaxIE9(method: string, url: string, data: any, headers?: any, options?: FullOptions) {
   return new Promise((resolve, reject) => {
+    // @ts-ignore
     const xdr = new XDomainRequest();
     xdr.onload = function () {
       let response;
@@ -77,7 +80,9 @@ function ajaxIE9(method: string, url: string, data: any, headers?: any, options?
     };
     xdr.open(method, url);
     xdr.send(data);
+    // @ts-ignore
     if (options && typeof options.requestTask === 'function') {
+      // @ts-ignore
       options.requestTask(xdr);
     }
   });
@@ -101,7 +106,7 @@ const RESTController = {
 
       const xhr = new XHR();
       xhr.onreadystatechange = function () {
-        if (xhr.readyState !== 4 || handled || xhr._aborted) {
+        if (xhr.readyState !== 4 || handled || (xhr as any)._aborted) {
           return;
         }
         handled = true;
@@ -203,7 +208,7 @@ const RESTController = {
     return promise;
   },
 
-  request(method: string, path: string, data: mixed, options?: RequestOptions) {
+  request(method: string, path: string, data: any, options?: RequestOptions) {
     options = options || {};
     let url = CoreManager.get('SERVER_URL');
     if (url[url.length - 1] !== '/') {
@@ -211,7 +216,18 @@ const RESTController = {
     }
     url += path;
 
-    const payload = {};
+    type PayloadType = {
+      _context?: any,
+      _method?: string,
+      _ApplicationId: string,
+      _JavaScriptKey?: string,
+      _ClientVersion: string,
+      _MasterKey?: string,
+      _RevocableSession?: string,
+      _InstallationId?: string,
+      _SessionToken?: string,
+    };
+    const payload: Partial = {};
     if (data && typeof data === 'object') {
       for (const k in data) {
         payload[k] = data[k];
@@ -254,7 +270,7 @@ const RESTController = {
     }
 
     const installationId = options.installationId;
-    let installationIdPromise;
+    let installationIdPromise: Promise;
     if (installationId && typeof installationId === 'string') {
       installationIdPromise = Promise.resolve(installationId);
     } else {
@@ -297,7 +313,7 @@ const RESTController = {
       .catch(RESTController.handleError);
   },
 
-  handleError(response) {
+  handleError(response: any) {
     // Transform the error into an instance of ParseError by trying to parse
     // the error string as JSON
     let error;
diff --git a/src/SingleInstanceStateController.js b/src/SingleInstanceStateController.ts
similarity index 94%
rename from src/SingleInstanceStateController.js
rename to src/SingleInstanceStateController.ts
index 3dd9c2cc7..d3296c25a 100644
--- a/src/SingleInstanceStateController.js
+++ b/src/SingleInstanceStateController.ts
@@ -18,7 +18,7 @@ let objectState: {
   },
 } = {};
 
-export function getState(obj: ObjectIdentifier): ?State {
+export function getState(obj: ObjectIdentifier): State | null {
   const classData = objectState[obj.className];
   if (classData) {
     return classData[obj.id] || null;
@@ -41,7 +41,7 @@ export function initializeState(obj: ObjectIdentifier, initial?: State): State {
   return state;
 }
 
-export function removeState(obj: ObjectIdentifier): ?State {
+export function removeState(obj: ObjectIdentifier): State | null {
   const state = getState(obj);
   if (state === null) {
     return null;
@@ -71,7 +71,7 @@ export function getPendingOps(obj: ObjectIdentifier): Array {
   return [{}];
 }
 
-export function setPendingOp(obj: ObjectIdentifier, attr: string, op: ?Op) {
+export function setPendingOp(obj: ObjectIdentifier, attr: string, op?: Op) {
   const pendingOps = initializeState(obj).pendingOps;
   ObjectStateMutations.setPendingOp(pendingOps, attr, op);
 }
@@ -99,7 +99,7 @@ export function getObjectCache(obj: ObjectIdentifier): ObjectCache {
   return {};
 }
 
-export function estimateAttribute(obj: ObjectIdentifier, attr: string): mixed {
+export function estimateAttribute(obj: ObjectIdentifier, attr: string): any {
   const serverData = getServerData(obj);
   const pendingOps = getPendingOps(obj);
   return ObjectStateMutations.estimateAttribute(
@@ -122,7 +122,7 @@ export function commitServerChanges(obj: ObjectIdentifier, changes: AttributeMap
   ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes);
 }
 
-export function enqueueTask(obj: ObjectIdentifier, task: () => Promise): Promise {
+export function enqueueTask(obj: ObjectIdentifier, task: () => Promise): Promise {
   const state = initializeState(obj);
   return state.tasks.enqueue(task);
 }
diff --git a/src/Storage.js b/src/Storage.ts
similarity index 93%
rename from src/Storage.js
rename to src/Storage.ts
index 67392c249..0af496743 100644
--- a/src/Storage.js
+++ b/src/Storage.ts
@@ -10,7 +10,7 @@ const Storage = {
     return !!controller.async;
   },
 
-  getItem(path: string): ?string {
+  getItem(path: string): string | null {
     const controller = CoreManager.getStorageController();
     if (controller.async === 1) {
       throw new Error('Synchronous storage is not supported by the current storage controller');
@@ -18,7 +18,7 @@ const Storage = {
     return controller.getItem(path);
   },
 
-  getItemAsync(path: string): Promise {
+  getItemAsync(path: string): Promise {
     const controller = CoreManager.getStorageController();
     if (controller.async === 1) {
       return controller.getItemAsync(path);
@@ -63,15 +63,15 @@ const Storage = {
     if (controller.async === 1) {
       throw new Error('Synchronous storage is not supported by the current storage controller');
     }
-    return controller.getAllKeys();
+    return controller.getAllKeys!();
   },
 
   getAllKeysAsync(): Promise> {
     const controller = CoreManager.getStorageController();
     if (controller.async === 1) {
-      return controller.getAllKeysAsync();
+      return controller.getAllKeysAsync!();
     }
-    return Promise.resolve(controller.getAllKeys());
+    return Promise.resolve(controller.getAllKeys!());
   },
 
   generatePath(path: string): string {
diff --git a/src/StorageController.browser.js b/src/StorageController.browser.ts
similarity index 83%
rename from src/StorageController.browser.js
rename to src/StorageController.browser.ts
index 0fdcd37b7..86d3f7404 100644
--- a/src/StorageController.browser.js
+++ b/src/StorageController.browser.ts
@@ -7,7 +7,7 @@
 const StorageController = {
   async: 0,
 
-  getItem(path: string): ?string {
+  getItem(path: string): string | null {
     return localStorage.getItem(path);
   },
 
@@ -25,9 +25,9 @@ const StorageController = {
   },
 
   getAllKeys() {
-    const keys = [];
+    const keys: string[] = [];
     for (let i = 0; i < localStorage.length; i += 1) {
-      keys.push(localStorage.key(i));
+      keys.push(localStorage.key(i) as string);
     }
     return keys;
   },
diff --git a/src/TaskQueue.js b/src/TaskQueue.ts
similarity index 80%
rename from src/TaskQueue.js
rename to src/TaskQueue.ts
index eedd769fe..55d45b757 100644
--- a/src/TaskQueue.js
+++ b/src/TaskQueue.ts
@@ -4,8 +4,8 @@
 import { resolvingPromise } from './promiseUtils';
 
 type Task = {
-  task: () => Promise,
-  _completion: Promise,
+  task: () => Promise,
+  _completion: ReturnType>,
 };
 
 class TaskQueue {
@@ -15,8 +15,8 @@ class TaskQueue {
     this.queue = [];
   }
 
-  enqueue(task: () => Promise): Promise {
-    const taskComplete = new resolvingPromise();
+  enqueue(task: () => Promise): Promise {
+    const taskComplete = resolvingPromise();
     this.queue.push({
       task: task,
       _completion: taskComplete,
@@ -55,3 +55,4 @@ class TaskQueue {
 }
 
 module.exports = TaskQueue;
+export default TaskQueue;
diff --git a/src/UniqueInstanceStateController.js b/src/UniqueInstanceStateController.ts
similarity index 93%
rename from src/UniqueInstanceStateController.js
rename to src/UniqueInstanceStateController.ts
index aaf21da10..50260209b 100644
--- a/src/UniqueInstanceStateController.js
+++ b/src/UniqueInstanceStateController.ts
@@ -11,7 +11,7 @@ import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMuta
 
 let objectState = new WeakMap();
 
-export function getState(obj: ParseObject): ?State {
+export function getState(obj: ParseObject): State | null | undefined {
   const classData = objectState.get(obj);
   return classData || null;
 }
@@ -35,7 +35,7 @@ export function initializeState(obj: ParseObject, initial?: State): State {
   return state;
 }
 
-export function removeState(obj: ParseObject): ?State {
+export function removeState(obj: ParseObject): State | null | undefined {
   const state = getState(obj);
   if (state === null) {
     return null;
@@ -65,7 +65,7 @@ export function getPendingOps(obj: ParseObject): Array {
   return [{}];
 }
 
-export function setPendingOp(obj: ParseObject, attr: string, op: ?Op) {
+export function setPendingOp(obj: ParseObject, attr: string, op?: Op) {
   const pendingOps = initializeState(obj).pendingOps;
   ObjectStateMutations.setPendingOp(pendingOps, attr, op);
 }
@@ -93,7 +93,7 @@ export function getObjectCache(obj: ParseObject): ObjectCache {
   return {};
 }
 
-export function estimateAttribute(obj: ParseObject, attr: string): mixed {
+export function estimateAttribute(obj: ParseObject, attr: string): any {
   const serverData = getServerData(obj);
   const pendingOps = getPendingOps(obj);
   return ObjectStateMutations.estimateAttribute(
@@ -116,7 +116,7 @@ export function commitServerChanges(obj: ParseObject, changes: AttributeMap) {
   ObjectStateMutations.commitServerChanges(state.serverData, state.objectCache, changes);
 }
 
-export function enqueueTask(obj: ParseObject, task: () => Promise): Promise {
+export function enqueueTask(obj: ParseObject, task: () => Promise): Promise {
   const state = initializeState(obj);
   return state.tasks.enqueue(task);
 }
diff --git a/src/arrayContainsObject.js b/src/arrayContainsObject.ts
similarity index 96%
rename from src/arrayContainsObject.js
rename to src/arrayContainsObject.ts
index ca9356849..9682cf108 100644
--- a/src/arrayContainsObject.js
+++ b/src/arrayContainsObject.ts
@@ -1,7 +1,3 @@
-/**
- * @flow
- */
-
 import ParseObject from './ParseObject';
 
 export default function arrayContainsObject(array: Array, object: ParseObject): boolean {
diff --git a/src/canBeSerialized.js b/src/canBeSerialized.ts
similarity index 100%
rename from src/canBeSerialized.js
rename to src/canBeSerialized.ts
diff --git a/src/decode.js b/src/decode.ts
similarity index 96%
rename from src/decode.js
rename to src/decode.ts
index 557002015..1c33b843e 100644
--- a/src/decode.js
+++ b/src/decode.ts
@@ -9,12 +9,13 @@ import ParseObject from './ParseObject';
 import { opFromJSON } from './ParseOp';
 import ParseRelation from './ParseRelation';
 
+/** Decodes values from storage type */
 export default function decode(value: any): any {
   if (value === null || typeof value !== 'object' || value instanceof Date) {
     return value;
   }
   if (Array.isArray(value)) {
-    const dup = [];
+    const dup: any = [];
     value.forEach((v, i) => {
       dup[i] = decode(v);
     });
diff --git a/src/encode.js b/src/encode.ts
similarity index 91%
rename from src/encode.js
rename to src/encode.ts
index 0214990f5..48350de06 100644
--- a/src/encode.js
+++ b/src/encode.ts
@@ -10,11 +10,12 @@ import ParseObject from './ParseObject';
 import { Op } from './ParseOp';
 import ParseRelation from './ParseRelation';
 
+/** Encodes values to storage type */
 function encode(
-  value: mixed,
+  value: any,
   disallowObjects: boolean,
   forcePointers: boolean,
-  seen: Array,
+  seen: Array,
   offline: boolean
 ): any {
   if (value instanceof ParseObject) {
@@ -56,7 +57,7 @@ function encode(
     if (isNaN(value)) {
       throw new Error('Tried to encode an invalid date.');
     }
-    return { __type: 'Date', iso: (value: any).toJSON() };
+    return { __type: 'Date', iso: (value as any).toJSON() };
   }
   if (
     Object.prototype.toString.call(value) === '[object RegExp]' &&
@@ -82,11 +83,12 @@ function encode(
   return value;
 }
 
+/** Encodes values to storage type */
 export default function (
-  value: mixed,
+  value: any,
   disallowObjects?: boolean,
   forcePointers?: boolean,
-  seen?: Array,
+  seen?: Array,
   offline?: boolean
 ): any {
   return encode(value, !!disallowObjects, !!forcePointers, seen || [], offline);
diff --git a/src/equals.js b/src/equals.ts
similarity index 95%
rename from src/equals.js
rename to src/equals.ts
index 3af927c99..234141519 100644
--- a/src/equals.js
+++ b/src/equals.ts
@@ -3,7 +3,7 @@ import ParseFile from './ParseFile';
 import ParseGeoPoint from './ParseGeoPoint';
 import ParseObject from './ParseObject';
 
-export default function equals(a, b) {
+export default function equals(a: any, b: any): boolean {
   const toString = Object.prototype.toString;
   if (toString.call(a) === '[object Date]' || toString.call(b) === '[object Date]') {
     const dateA = new Date(a);
diff --git a/src/escape.js b/src/escape.ts
similarity index 100%
rename from src/escape.js
rename to src/escape.ts
diff --git a/src/isRevocableSession.js b/src/isRevocableSession.ts
similarity index 100%
rename from src/isRevocableSession.js
rename to src/isRevocableSession.ts
diff --git a/src/parseDate.js b/src/parseDate.ts
similarity index 90%
rename from src/parseDate.js
rename to src/parseDate.ts
index 04ff6ea7f..8de789d67 100644
--- a/src/parseDate.js
+++ b/src/parseDate.ts
@@ -2,7 +2,7 @@
  * @flow
  */
 
-export default function parseDate(iso8601: string): ?Date {
+export default function parseDate(iso8601: string): Date | null {
   const regexp = new RegExp(
     '^([0-9]{1,4})-([0-9]{1,2})-([0-9]{1,2})' +
       'T' +
diff --git a/src/promiseUtils.js b/src/promiseUtils.ts
similarity index 64%
rename from src/promiseUtils.js
rename to src/promiseUtils.ts
index 176c32a0b..aa3d2d153 100644
--- a/src/promiseUtils.js
+++ b/src/promiseUtils.ts
@@ -1,30 +1,31 @@
 // Create Deferred Promise
-export function resolvingPromise() {
-  let res;
-  let rej;
-  const promise = new Promise((resolve, reject) => {
+export function resolvingPromise() {
+  let res: (val: T) => void;
+  let rej: (err: any) => void;
+  const promise = new Promise((resolve, reject) => {
     res = resolve;
     rej = reject;
   });
-  promise.resolve = res;
-  promise.reject = rej;
-  return promise;
+  const ret: typeof promise & { resolve: (res: T) => void, reject: (err: any) => void } = promise as any;
+  ret.resolve = res!;
+  ret.reject = rej!;
+  return ret;
 }
 
-export function when(promises) {
-  let objects;
+export function when(promises: Promise | Promise[]) {
+  let objects: Promise[];
   const arrayArgument = Array.isArray(promises);
   if (arrayArgument) {
     objects = promises;
   } else {
-    objects = arguments;
+    objects = [promises];
   }
 
   let total = objects.length;
   let hadError = false;
-  const results = [];
+  const results: any[] = [];
   const returnValue = arrayArgument ? [results] : results;
-  const errors = [];
+  const errors: any[] = [];
   results.length = objects.length;
   errors.length = objects.length;
 
@@ -32,7 +33,7 @@ export function when(promises) {
     return Promise.resolve(returnValue);
   }
 
-  const promise = new resolvingPromise();
+  const promise = resolvingPromise();
 
   const resolveOne = function () {
     total--;
@@ -45,7 +46,7 @@ export function when(promises) {
     }
   };
 
-  const chain = function (object, index) {
+  const chain = function (object: Promise, index: number) {
     if (object && typeof object.then === 'function') {
       object.then(
         function (result) {
@@ -66,11 +67,10 @@ export function when(promises) {
   for (let i = 0; i < objects.length; i++) {
     chain(objects[i], i);
   }
-
   return promise;
 }
 
-export function continueWhile(test, emitter) {
+export function continueWhile(test: () => boolean, emitter: () => Promise) {
   if (test()) {
     return emitter().then(() => {
       return continueWhile(test, emitter);
diff --git a/src/unique.js b/src/unique.ts
similarity index 100%
rename from src/unique.js
rename to src/unique.ts
diff --git a/src/uuid.js b/src/uuid.ts
similarity index 67%
rename from src/uuid.js
rename to src/uuid.ts
index 450d4976c..401427d20 100644
--- a/src/uuid.js
+++ b/src/uuid.ts
@@ -1,8 +1,8 @@
-let uuid = null;
+let uuid: () => string = null as any;
 
 if (process.env.PARSE_BUILD === 'weapp') {
   uuid = function () {
-    const s = [];
+    const s: string[] = [];
     const hexDigits = '0123456789abcdef';
 
     for (let i = 0; i < 36; i++) {
@@ -10,9 +10,8 @@ if (process.env.PARSE_BUILD === 'weapp') {
     }
 
     s[14] = '4'; // bits 12-15 of the time_hi_and_version field to 0010
-    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
+    s[19] = hexDigits.substr((Number(s[19]) & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
     s[8] = s[13] = s[18] = s[23] = '-';
-
     return s.join('');
   };
 } else {
@@ -20,4 +19,4 @@ if (process.env.PARSE_BUILD === 'weapp') {
   uuid = v4;
 }
 
-module.exports = uuid;
+export default uuid;

From 1ab624971514c196dd00477995c629c5e40bf9ef Mon Sep 17 00:00:00 2001
From: Switt Kongdachalert 
Date: Sun, 29 Oct 2023 18:05:01 +0700
Subject: [PATCH 09/27] more

---
 src/{Analytics.js => Analytics.ts}           | 4 ++--
 src/{AnonymousUtils.js => AnonymousUtils.ts} | 2 +-
 src/CoreManager.ts                           | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)
 rename src/{Analytics.js => Analytics.ts} (95%)
 rename src/{AnonymousUtils.js => AnonymousUtils.ts} (99%)

diff --git a/src/Analytics.js b/src/Analytics.ts
similarity index 95%
rename from src/Analytics.js
rename to src/Analytics.ts
index 32f4cf82f..3a6b367c3 100644
--- a/src/Analytics.js
+++ b/src/Analytics.ts
@@ -44,7 +44,7 @@ import CoreManager from './CoreManager';
  * @returns {Promise} A promise that is resolved when the round-trip
  * to the server completes.
  */
-export function track(name: string, dimensions: { [key: string]: string }): Promise {
+export function track(name: string, dimensions: { [key: string]: string }): Promise {
   name = name || '';
   name = name.replace(/^\s*/, '');
   name = name.replace(/\s*$/, '');
@@ -62,7 +62,7 @@ export function track(name: string, dimensions: { [key: string]: string }): Prom
 }
 
 const DefaultController = {
-  track(name, dimensions) {
+  track(name: string, dimensions: { [key: string]: string }) {
     const path = 'events/' + name;
     const RESTController = CoreManager.getRESTController();
     return RESTController.request('POST', path, { dimensions: dimensions });
diff --git a/src/AnonymousUtils.js b/src/AnonymousUtils.ts
similarity index 99%
rename from src/AnonymousUtils.js
rename to src/AnonymousUtils.ts
index 2472f8b7d..9950af8dd 100644
--- a/src/AnonymousUtils.js
+++ b/src/AnonymousUtils.ts
@@ -4,7 +4,7 @@
 
 import ParseUser from './ParseUser';
 import type { RequestOptions } from './RESTController';
-const uuidv4 = require('./uuid');
+import uuidv4 from './uuid';
 
 let registered = false;
 
diff --git a/src/CoreManager.ts b/src/CoreManager.ts
index 577d1796c..b9436758b 100644
--- a/src/CoreManager.ts
+++ b/src/CoreManager.ts
@@ -74,7 +74,7 @@ type QueryController = {
   aggregate: (className: string, params: any, options: RequestOptions) => Promise,
 };
 type RESTController = {
-  request: (method: string, path: string, data: any, options: RequestOptions) => Promise,
+  request: (method: string, path: string, data: any, options?: RequestOptions) => Promise,
   ajax: (method: string, url: string, data: any, headers?: any, options?: FullOptions) => Promise,
   handleError: (err?: any) => void,
 };

From 7188bff85d78d7b767c2473d7fe35bd47ce162d2 Mon Sep 17 00:00:00 2001
From: Switt Kongdachalert 
Date: Sun, 29 Oct 2023 21:33:13 +0700
Subject: [PATCH 10/27] moar types

---
 src/CoreManager.ts                            |  47 +++--
 src/EventEmitter.ts                           |   2 +-
 ...{LiveQueryClient.js => LiveQueryClient.ts} | 187 +++++++++---------
 src/LiveQuerySubscription.ts                  |  11 +-
 src/{ParseACL.js => ParseACL.ts}              |  12 +-
 src/{ParseLiveQuery.js => ParseLiveQuery.ts}  |  12 +-
 src/ParseObject.ts                            |   1 +
 src/{ParsePolygon.js => ParsePolygon.ts}      |  10 +-
 src/{ParseQuery.js => ParseQuery.ts}          | 170 +++++++++-------
 src/{ParseUser.js => ParseUser.ts}            | 124 ++++++------
 src/{Push.js => Push.ts}                      |  11 +-
 11 files changed, 330 insertions(+), 257 deletions(-)
 rename src/{LiveQueryClient.js => LiveQueryClient.ts} (75%)
 rename src/{ParseACL.js => ParseACL.ts} (98%)
 rename src/{ParseLiveQuery.js => ParseLiveQuery.ts} (95%)
 rename src/{ParsePolygon.js => ParsePolygon.ts} (94%)
 rename src/{ParseQuery.js => ParseQuery.ts} (93%)
 rename src/{ParseUser.js => ParseUser.ts} (92%)
 rename src/{Push.js => Push.ts} (89%)

diff --git a/src/CoreManager.ts b/src/CoreManager.ts
index b9436758b..57c6877b4 100644
--- a/src/CoreManager.ts
+++ b/src/CoreManager.ts
@@ -11,6 +11,7 @@ import type { RequestOptions, FullOptions } from './RESTController';
 import type ParseSession from './ParseSession';
 import type { HookDeclaration, HookDeleteArg } from './ParseHooks';
 import type ParseConfig from './ParseConfig';
+import type LiveQueryClient from './LiveQueryClient';
 
 type AnalyticsController = {
   track: (name: string, dimensions: { [key: string]: string }) => Promise,
@@ -67,11 +68,11 @@ type ObjectStateController = {
   duplicateState: (source: any, dest: any) => void,
 };
 type PushController = {
-  send: (data: PushData) => Promise,
+  send: (data: PushData, options?: FullOptions) => Promise,
 };
 type QueryController = {
-  find: (className: string, params: QueryJSON, options: RequestOptions) => Promise,
-  aggregate: (className: string, params: any, options: RequestOptions) => Promise,
+  find(className: string, params: QueryJSON, options: RequestOptions): Promise<{ results?: Array, className?: string, count?: number }>;
+  aggregate(className: string, params: any, options: RequestOptions): Promise<{ results?: Array }>;
 };
 type RESTController = {
   request: (method: string, path: string, data: any, options?: RequestOptions) => Promise,
@@ -125,18 +126,19 @@ type UserController = {
   setCurrentUser: (user: ParseUser) => Promise,
   currentUser: () => ParseUser | undefined,
   currentUserAsync: () => Promise,
-  signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise,
-  logIn: (user: ParseUser, options: RequestOptions) => Promise,
-  become: (options: RequestOptions) => Promise,
-  hydrate: (userJSON: AttributeMap) => Promise,
+  signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise,
+  logIn: (user: ParseUser, options: RequestOptions) => Promise,
+  loginAs: (user: ParseUser, userId: string) => Promise,
+  become: (user: ParseUser, options: RequestOptions) => Promise,
+  hydrate: (user: ParseUser, userJSON: AttributeMap) => Promise,
   logOut: (options: RequestOptions) => Promise,
-  me: (options: RequestOptions) => Promise,
+  me: (user: ParseUser, options: RequestOptions) => Promise,
   requestPasswordReset: (email: string, options: RequestOptions) => Promise,
-  updateUserOnDisk: (user: ParseUser) => Promise,
+  updateUserOnDisk: (user: ParseUser) => Promise,
   upgradeToRevocableSession: (user: ParseUser, options: RequestOptions) => Promise,
-  linkWith: (user: ParseUser, authData: AuthData) => Promise,
-  removeUserFromDisk: () => Promise,
-  verifyPassword: (username: string, password: string, options: RequestOptions) => Promise,
+  linkWith: (user: ParseUser, authData: AuthData, options?: FullOptions) => Promise,
+  removeUserFromDisk: () => Promise,
+  verifyPassword: (username: string, password: string, options: RequestOptions) => Promise,
   requestEmailVerification: (email: string, options: RequestOptions) => Promise,
 };
 type HooksController = {
@@ -147,10 +149,16 @@ type HooksController = {
   // Renamed to sendRequest since ParseHooks file & tests file uses this. (originally declared as just "send")
   sendRequest?: (method: string, path: string, body?: any) => Promise,
 };
-type WebSocketController = {
+type LiveQueryControllerType = {
+  setDefaultLiveQueryClient(liveQueryClient: LiveQueryClient): void;
+  getDefaultLiveQueryClient(): Promise;
+  _clearCachedDefaultClient(): void;
+}
+
+export type WebSocketController = {
   onopen: () => void,
   onmessage: (message: any) => void,
-  onclose: () => void,
+  onclose: (arg?: any) => void,
   onerror: (error: any) => void,
   send: (data: any) => void,
   close: () => void,
@@ -172,7 +180,8 @@ type Config = {
   LocalDatastoreController?: LocalDatastoreController,
   UserController?: UserController,
   HooksController?: HooksController,
-  WebSocketController?: WebSocketController,
+  WebSocketController?: new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController,
+  LiveQueryController?: LiveQueryControllerType
 };
 
 const config: Config & { [key: string]: any } = {
@@ -441,11 +450,11 @@ const CoreManager = {
     return config['AsyncStorage'];
   },
 
-  setWebSocketController(controller: WebSocketController) {
+  setWebSocketController(controller: new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController) {
     config['WebSocketController'] = controller;
   },
 
-  getWebSocketController(): WebSocketController {
+  getWebSocketController(): new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController {
     return config['WebSocketController'];
   },
 
@@ -476,7 +485,7 @@ const CoreManager = {
     return config['UserController'];
   },
 
-  setLiveQueryController(controller: any) {
+  setLiveQueryController(controller: LiveQueryControllerType) {
     requireMethods(
       'LiveQueryController',
       ['setDefaultLiveQueryClient', 'getDefaultLiveQueryClient', '_clearCachedDefaultClient'],
@@ -485,7 +494,7 @@ const CoreManager = {
     config['LiveQueryController'] = controller;
   },
 
-  getLiveQueryController(): any {
+  getLiveQueryController(): LiveQueryControllerType {
     return config['LiveQueryController'];
   },
 
diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts
index 8e313f092..cb6897c0f 100644
--- a/src/EventEmitter.ts
+++ b/src/EventEmitter.ts
@@ -3,7 +3,7 @@ import type { EventEmitter as EventEmitterType } from 'events';
  * This is a simple wrapper to unify EventEmitter implementations across platforms.
  */
 
-let EventEmitter: new (...args: ConstructorParameters) => EventEmitterType;
+let EventEmitter: typeof EventEmitterType;
 
 try {
   if (process.env.PARSE_BUILD === 'react-native') {
diff --git a/src/LiveQueryClient.js b/src/LiveQueryClient.ts
similarity index 75%
rename from src/LiveQueryClient.js
rename to src/LiveQueryClient.ts
index 790624fbf..d942cb530 100644
--- a/src/LiveQueryClient.js
+++ b/src/LiveQueryClient.ts
@@ -1,10 +1,12 @@
 /* global WebSocket */
 
-import CoreManager from './CoreManager';
+import CoreManager, { WebSocketController } from './CoreManager';
 import ParseObject from './ParseObject';
 import LiveQuerySubscription from './LiveQuerySubscription';
 import { resolvingPromise } from './promiseUtils';
 import ParseError from './ParseError';
+import type { EventEmitter } from 'events';
+import type ParseQuery from './ParseQuery';
 
 // The LiveQuery client inner state
 const CLIENT_STATE = {
@@ -109,15 +111,19 @@ class LiveQueryClient {
   requestId: number;
   applicationId: string;
   serverURL: string;
-  javascriptKey: ?string;
-  masterKey: ?string;
-  sessionToken: ?string;
-  installationId: ?string;
+  javascriptKey?: string;
+  masterKey?: string;
+  sessionToken?: string;
+  installationId?: string;
   additionalProperties: boolean;
-  connectPromise: Promise;
-  subscriptions: Map;
-  socket: any;
+  connectPromise: ReturnType>;
+  subscriptions: Map;
+  socket: WebSocketController & { closingPromise?: ReturnType> };
   state: string;
+  reconnectHandle: null | ReturnType = null;
+  emitter: EventEmitter;
+  on: EventEmitter['on'];
+  emit: EventEmitter['emit'];
 
   /**
    * @param {object} options
@@ -156,14 +162,14 @@ class LiveQueryClient {
     this.connectPromise = resolvingPromise();
     this.subscriptions = new Map();
     this.state = CLIENT_STATE.INITIALIZED;
-    const EventEmitter = CoreManager.getEventEmitter();
+    const EventEmitter = CoreManager.getEventEmitter() as new () => EventEmitter;
     this.emitter = new EventEmitter();
 
     this.on = this.emitter.on;
     this.emit = this.emitter.emit;
     // adding listener so process does not crash
     // best practice is for developer to register their own listener
-    this.on('error', () => {});
+    this.on('error', () => { });
   }
 
   shouldOpen(): any {
@@ -184,7 +190,7 @@ class LiveQueryClient {
    * @param {string} sessionToken (optional)
    * @returns {LiveQuerySubscription | undefined}
    */
-  subscribe(query: Object, sessionToken: ?string): LiveQuerySubscription {
+  subscribe(query: ParseQuery, sessionToken?: string): LiveQuerySubscription | undefined {
     if (!query) {
       return;
     }
@@ -202,6 +208,7 @@ class LiveQueryClient {
         fields,
         watch,
       },
+      sessionToken: undefined as string | undefined
     };
 
     if (sessionToken) {
@@ -228,7 +235,7 @@ class LiveQueryClient {
    * @param {object} subscription - subscription you would like to unsubscribe from.
    * @returns {Promise | undefined}
    */
-  unsubscribe(subscription: Object): ?Promise {
+  async unsubscribe(subscription: LiveQuerySubscription): Promise {
     if (!subscription) {
       return;
     }
@@ -272,7 +279,7 @@ class LiveQueryClient {
     };
 
     this.socket.onclose = (event) => {
-      this.socket.closingPromise.resolve(event);
+      this.socket.closingPromise!.resolve(event);
       this._handleWebSocketClose();
     };
 
@@ -297,6 +304,7 @@ class LiveQueryClient {
           where,
           fields,
         },
+        sessionToken: undefined as string | undefined
       };
 
       if (sessionToken) {
@@ -315,7 +323,7 @@ class LiveQueryClient {
    *
    * @returns {Promise | undefined} CloseEvent {@link https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/close_event}
    */
-  close(): ?Promise {
+  async close(): Promise {
     if (this.state === CLIENT_STATE.INITIALIZED || this.state === CLIENT_STATE.DISCONNECTED) {
       return;
     }
@@ -348,6 +356,7 @@ class LiveQueryClient {
       javascriptKey: this.javascriptKey,
       masterKey: this.masterKey,
       sessionToken: this.sessionToken,
+      installationId: undefined as string | undefined
     };
     if (this.additionalProperties) {
       connectRequest.installationId = this.installationId;
@@ -360,96 +369,96 @@ class LiveQueryClient {
     if (typeof data === 'string') {
       data = JSON.parse(data);
     }
-    let subscription = null;
+    let subscription: null | LiveQuerySubscription = null;
     if (data.requestId) {
-      subscription = this.subscriptions.get(data.requestId);
+      subscription = this.subscriptions.get(data.requestId) || null;
     }
     const response = {
       clientId: data.clientId,
       installationId: data.installationId,
     };
     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.subscribed = true;
-        subscription.subscribePromise.resolve();
-        setTimeout(() => subscription.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN, response), 200);
-      }
-      break;
-    case OP_EVENTS.ERROR: {
-      const parseError = new ParseError(data.code, data.error);
-      if (!this.id) {
-        this.connectPromise.reject(parseError);
-        this.state = CLIENT_STATE.DISCONNECTED;
-      }
-      if (data.requestId) {
+      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.subscribePromise.reject(parseError);
-          setTimeout(() => subscription.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error), 200);
+          subscription.subscribed = true;
+          subscription.subscribePromise.resolve();
+          setTimeout(() => subscription!.emit(SUBSCRIPTION_EMMITER_TYPES.OPEN, response), 200);
         }
-      } else {
-        this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error);
-      }
-      if (data.error === 'Additional properties not allowed') {
-        this.additionalProperties = false;
-      }
-      if (data.reconnect) {
-        this._handleReconnect();
-      }
-      break;
-    }
-    case OP_EVENTS.UNSUBSCRIBED: {
-      if (subscription) {
-        this.subscriptions.delete(data.requestId);
-        subscription.subscribed = false;
-        subscription.unsubscribePromise.resolve();
-      }
-      break;
-    }
-    default: {
-      // create, update, enter, leave, delete cases
-      if (!subscription) {
         break;
-      }
-      let override = false;
-      if (data.original) {
-        override = true;
-        delete data.original.__type;
-        // Check for removed fields
-        for (const field in data.original) {
-          if (!(field in data.object)) {
-            data.object[field] = undefined;
+      case OP_EVENTS.ERROR: {
+        const parseError = new ParseError(data.code, data.error);
+        if (!this.id) {
+          this.connectPromise.reject(parseError);
+          this.state = CLIENT_STATE.DISCONNECTED;
+        }
+        if (data.requestId) {
+          if (subscription) {
+            subscription.subscribePromise.reject(parseError);
+            setTimeout(() => subscription!.emit(SUBSCRIPTION_EMMITER_TYPES.ERROR, data.error), 200);
           }
+        } else {
+          this.emit(CLIENT_EMMITER_TYPES.ERROR, data.error);
+        }
+        if (data.error === 'Additional properties not allowed') {
+          this.additionalProperties = false;
         }
-        data.original = ParseObject.fromJSON(data.original, false);
+        if (data.reconnect) {
+          this._handleReconnect();
+        }
+        break;
       }
-      delete data.object.__type;
-      const parseObject = ParseObject.fromJSON(
-        data.object,
-        !(subscription.query && subscription.query._select) ? override : false
-      );
-
-      if (data.original) {
-        subscription.emit(data.op, parseObject, data.original, response);
-      } else {
-        subscription.emit(data.op, parseObject, response);
+      case OP_EVENTS.UNSUBSCRIBED: {
+        if (subscription) {
+          this.subscriptions.delete(data.requestId);
+          subscription.subscribed = false;
+          subscription.unsubscribePromise.resolve();
+        }
+        break;
       }
+      default: {
+        // create, update, enter, leave, delete cases
+        if (!subscription) {
+          break;
+        }
+        let override = false;
+        if (data.original) {
+          override = true;
+          delete data.original.__type;
+          // Check for removed fields
+          for (const field in data.original) {
+            if (!(field in data.object)) {
+              data.object[field] = undefined;
+            }
+          }
+          data.original = ParseObject.fromJSON(data.original, false);
+        }
+        delete data.object.__type;
+        const parseObject = ParseObject.fromJSON(
+          data.object,
+          !(subscription.query && subscription.query._select) ? override : false
+        );
+
+        if (data.original) {
+          subscription.emit(data.op, parseObject, data.original, response);
+        } else {
+          subscription.emit(data.op, parseObject, response);
+        }
 
-      const localDatastore = CoreManager.getLocalDatastore();
-      if (override && localDatastore.isEnabled) {
-        localDatastore._updateObjectIfPinned(parseObject).then(() => {});
+        const localDatastore = CoreManager.getLocalDatastore();
+        if (override && localDatastore.isEnabled) {
+          localDatastore._updateObjectIfPinned(parseObject).then(() => { });
+        }
       }
     }
-    }
   }
 
   _handleWebSocketClose() {
@@ -506,12 +515,12 @@ if (process.env.PARSE_BUILD === 'node') {
   CoreManager.setWebSocketController(require('ws'));
 } else if (process.env.PARSE_BUILD === 'browser') {
   CoreManager.setWebSocketController(
-    typeof WebSocket === 'function' || typeof WebSocket === 'object' ? WebSocket : null
+    typeof WebSocket === 'function' || typeof WebSocket === 'object' ? WebSocket : null as any
   );
 } else if (process.env.PARSE_BUILD === 'weapp') {
   CoreManager.setWebSocketController(require('./Socket.weapp'));
 } else if (process.env.PARSE_BUILD === 'react-native') {
-  CoreManager.setWebSocketController(WebSocket);
+  CoreManager.setWebSocketController(WebSocket as any);
 }
 
 export default LiveQueryClient;
diff --git a/src/LiveQuerySubscription.ts b/src/LiveQuerySubscription.ts
index 5e7764b67..62ff1de4f 100644
--- a/src/LiveQuerySubscription.ts
+++ b/src/LiveQuerySubscription.ts
@@ -2,6 +2,7 @@ import type { EventEmitter } from 'events';
 import CoreManager from './CoreManager';
 import AnEventEmitter from './EventEmitter';
 import { resolvingPromise } from './promiseUtils';
+import type ParseQuery from './ParseQuery';
 
 /**
  * Creates a new LiveQuery Subscription.
@@ -86,11 +87,11 @@ import { resolvingPromise } from './promiseUtils';
  * });

*/ class Subscription { - id: string; - query: string; + id: string | number; + query: ParseQuery; sessionToken?: string; - subscribePromise: ReturnType; - unsubscribePromise: ReturnType; + subscribePromise: ReturnType>; + unsubscribePromise: ReturnType>; subscribed: boolean; emitter: EventEmitter; on: EventEmitter['on']; @@ -101,7 +102,7 @@ class Subscription { * @param {string} query - query to subscribe to * @param {string} sessionToken - optional session token */ - constructor(id: string, query: string, sessionToken?: string) { + constructor(id: string | number, query: ParseQuery, sessionToken?: string) { this.id = id; this.query = query; this.sessionToken = sessionToken; diff --git a/src/ParseACL.js b/src/ParseACL.ts similarity index 98% rename from src/ParseACL.js rename to src/ParseACL.ts index beedb6719..daf9d0ac8 100644 --- a/src/ParseACL.js +++ b/src/ParseACL.ts @@ -101,7 +101,7 @@ class ParseACL { _setAccess(accessType: string, userId: ParseUser | ParseRole | string, allowed: boolean) { if (userId instanceof ParseUser) { - userId = userId.id; + userId = userId.id!; } else if (userId instanceof ParseRole) { const name = userId.getName(); if (!name) { @@ -138,7 +138,7 @@ class ParseACL { _getAccess(accessType: string, userId: ParseUser | ParseRole | string): boolean { if (userId instanceof ParseUser) { - userId = userId.id; + userId = userId.id!; if (!userId) { throw new Error('Cannot get access for a ParseUser without an ID'); } @@ -250,7 +250,7 @@ class ParseACL { getRoleReadAccess(role: ParseRole | string): boolean { if (role instanceof ParseRole) { // Normalize to the String name - role = role.getName(); + role = role.getName()!; } if (typeof role !== 'string') { throw new TypeError('role must be a ParseRole or a String'); @@ -270,7 +270,7 @@ class ParseACL { getRoleWriteAccess(role: ParseRole | string): boolean { if (role instanceof ParseRole) { // Normalize to the String name - role = role.getName(); + role = role.getName()!; } if (typeof role !== 'string') { throw new TypeError('role must be a ParseRole or a String'); @@ -289,7 +289,7 @@ class ParseACL { setRoleReadAccess(role: ParseRole | string, allowed: boolean) { if (role instanceof ParseRole) { // Normalize to the String name - role = role.getName(); + role = role.getName()!; } if (typeof role !== 'string') { throw new TypeError('role must be a ParseRole or a String'); @@ -308,7 +308,7 @@ class ParseACL { setRoleWriteAccess(role: ParseRole | string, allowed: boolean) { if (role instanceof ParseRole) { // Normalize to the String name - role = role.getName(); + role = role.getName()!; } if (typeof role !== 'string') { throw new TypeError('role must be a ParseRole or a String'); diff --git a/src/ParseLiveQuery.js b/src/ParseLiveQuery.ts similarity index 95% rename from src/ParseLiveQuery.js rename to src/ParseLiveQuery.ts index eea9e59e2..0a507d6a6 100644 --- a/src/ParseLiveQuery.js +++ b/src/ParseLiveQuery.ts @@ -3,7 +3,7 @@ */ import LiveQueryClient from './LiveQueryClient'; import CoreManager from './CoreManager'; - +import type { EventEmitter } from 'events'; function getLiveQueryClient(): Promise { return CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); } @@ -36,6 +36,10 @@ function getLiveQueryClient(): Promise { * @static */ class LiveQuery { + emitter: EventEmitter; + on: EventEmitter['on']; + emit: EventEmitter['emit']; + constructor() { const EventEmitter = CoreManager.getEventEmitter(); this.emitter = new EventEmitter(); @@ -44,14 +48,14 @@ class LiveQuery { // adding listener so process does not crash // best practice is for developer to register their own listener - this.on('error', () => {}); + this.on('error', () => { }); } /** * After open is called, the LiveQuery will try to send a connect request * to the LiveQuery server. */ - async open(): void { + async open() { const liveQueryClient = await getLiveQueryClient(); liveQueryClient.open(); } @@ -63,7 +67,7 @@ class LiveQuery { * If you call query.subscribe() after this, we'll create a new WebSocket * connection to the LiveQuery server. */ - async close(): void { + async close() { const liveQueryClient = await getLiveQueryClient(); liveQueryClient.close(); } diff --git a/src/ParseObject.ts b/src/ParseObject.ts index 726fa3201..48b0a0012 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -153,6 +153,7 @@ class ParseObject { _localId?: string; _objCount: number; className: string; + static className: string; /* Prototype getters / setters */ diff --git a/src/ParsePolygon.js b/src/ParsePolygon.ts similarity index 94% rename from src/ParsePolygon.js rename to src/ParsePolygon.ts index a7887ea02..27a8ed367 100644 --- a/src/ParsePolygon.js +++ b/src/ParsePolygon.ts @@ -24,12 +24,12 @@ import ParseGeoPoint from './ParseGeoPoint'; * @alias Parse.Polygon */ class ParsePolygon { - _coordinates: Array>; + _coordinates: Array<[number, number]>; /** * @param {(number[][] | Parse.GeoPoint[])} coordinates An Array of coordinate pairs */ - constructor(coordinates: Array> | Array) { + constructor(coordinates: Array | [number, number]> | Array) { this._coordinates = ParsePolygon._validate(coordinates); } @@ -67,7 +67,7 @@ class ParsePolygon { * @param {(Parse.Polygon | object)} other * @returns {boolean} */ - equals(other: mixed): boolean { + equals(other: ParsePolygon | any): boolean { if (!(other instanceof ParsePolygon) || this.coordinates.length !== other.coordinates.length) { return false; } @@ -138,14 +138,14 @@ class ParsePolygon { * @throws {TypeError} * @returns {number[][]} Array of coordinates if validated. */ - static _validate(coords: Array> | Array): Array> { + static _validate(coords: Array> | Array): Array<[number, number]> { 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 = []; + const points: [number, number][] = []; for (let i = 0; i < coords.length; i += 1) { const coord = coords[i]; let geoPoint; diff --git a/src/ParseQuery.js b/src/ParseQuery.ts similarity index 93% rename from src/ParseQuery.js rename to src/ParseQuery.ts index 9be6b37a9..b1fb02305 100644 --- a/src/ParseQuery.js +++ b/src/ParseQuery.ts @@ -14,10 +14,47 @@ import { DEFAULT_PIN } from './LocalDatastoreUtils'; import type LiveQuerySubscription from './LiveQuerySubscription'; import type { RequestOptions, FullOptions } from './RESTController'; -type BatchOptions = FullOptions & { batchSize?: number }; +/** + * *
  • batchSize: How many objects to yield in each batch (default: 100) + *
  • 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. + *
  • context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. + * + */ +type BatchOptions = FullOptions & { + batchSize?: number + useMasterKey?: boolean, + sessionToken?: string, + context?: { [key: string]: any }, + json?: boolean +}; + +/** + * 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. + * context: A dictionary that is accessible in Cloud Code `beforeFind` trigger. + * json: Return raw json without converting to Parse.Object + */ +type QueryOptions = { + useMasterKey?: boolean, + sessionToken?: string, + context?: { [key: string]: any }, + json?: boolean +} +type FullTextQueryOptions = { + /** @param {string} options.language The language that determines the list of stop words for the search and the rules for the stemmer and tokenizer.*/ + language?: string, + /** @param {boolean} options.caseSensitive A boolean flag to enable or disable case sensitive search.*/ + caseSensitive?: boolean, + /** @param {boolean} options.diacriticSensitive A boolean flag to enable or disable diacritic sensitive search.*/ + diacriticSensitive?: boolean +} export type WhereClause = { - [attr: string]: mixed, + [attr: string]: any, }; export type QueryJSON = { @@ -31,7 +68,7 @@ export type QueryJSON = { order?: string, className?: string, count?: number, - hint?: mixed, + hint?: any, explain?: boolean, readPreference?: string, includeReadPreference?: string, @@ -59,7 +96,7 @@ function quote(s: string): string { * @private * @returns {string} */ -function _getClassNameFromQueries(queries: Array): ?string { +function _getClassNameFromQueries(queries: Array): string | null { let className = null; queries.forEach(q => { if (!className) { @@ -238,8 +275,8 @@ class ParseQuery { _subqueryReadPreference: string; _queriesLocalDatastore: boolean; _localDatastorePinName: any; - _extraOptions: { [key: string]: mixed }; - _hint: mixed; + _extraOptions: { [key: string]: any }; + _hint: any; _explain: boolean; _xhrRequest: any; @@ -256,10 +293,11 @@ class ParseQuery { } else if (objectClass instanceof ParseObject) { this.className = objectClass.className; } else if (typeof objectClass === 'function') { - if (typeof objectClass.className === 'string') { - this.className = objectClass.className; + const objectClz = (objectClass) as typeof ParseObject; + if (typeof objectClz.className === 'string') { + this.className = objectClass; } else { - const obj = new objectClass(); + const obj = new objectClz(); this.className = obj.className; } } else { @@ -281,7 +319,7 @@ class ParseQuery { this._extraOptions = {}; this._xhrRequest = { task: null, - onchange: () => {}, + onchange: () => { }, }; } @@ -338,7 +376,7 @@ class ParseQuery { * @param value * @returns {Parse.Query} */ - _addCondition(key: string, condition: string, value: mixed): ParseQuery { + _addCondition(key: string, condition: string, value: any): ParseQuery { if (!this._where[key] || typeof this._where[key] === 'string') { this._where[key] = {}; } @@ -609,10 +647,10 @@ class ParseQuery { * @returns {Promise} A promise that is resolved with the result when * the query completes. */ - get(objectId: string, options?: FullOptions): Promise { + get(objectId: string, options?: QueryOptions): Promise { this.equalTo('objectId', objectId); - const firstOptions = {}; + const firstOptions: QueryOptions = {}; if (options && options.hasOwnProperty('useMasterKey')) { firstOptions.useMasterKey = options.useMasterKey; } @@ -630,7 +668,6 @@ class ParseQuery { if (response) { return response; } - const errorObject = new ParseError(ParseError.OBJECT_NOT_FOUND, 'Object not found.'); return Promise.reject(errorObject); }); @@ -651,10 +688,10 @@ class ParseQuery { * @returns {Promise} A promise that is resolved with the results when * the query completes. */ - find(options?: FullOptions): Promise> { + find(options?: QueryOptions): Promise> { options = options || {}; - const findOptions = {}; + const findOptions: QueryOptions = {}; if (options.hasOwnProperty('useMasterKey')) { findOptions.useMasterKey = options.useMasterKey; } @@ -702,7 +739,7 @@ class ParseQuery { const count = response.count; if (typeof count === 'number') { - return { results, count }; + return { results, count } as any; } else { return results; } @@ -744,10 +781,10 @@ class ParseQuery { * @returns {Promise} A promise that is resolved with the count when * the query completes. */ - count(options?: FullOptions): Promise { + count(options?: { useMasterKey?: boolean, sessionToken?: string }): Promise { options = options || {}; - const findOptions = {}; + const findOptions: { useMasterKey?: boolean, sessionToken?: string } = {}; if (options.hasOwnProperty('useMasterKey')) { findOptions.useMasterKey = options.useMasterKey; } @@ -778,12 +815,10 @@ class ParseQuery { * * @returns {Promise} A promise that is resolved with the query completes. */ - distinct(key: string, options?: FullOptions): Promise> { + distinct(key: string, options?: { sessionToken?: string }): Promise> { options = options || {}; - const distinctOptions = {}; - distinctOptions.useMasterKey = true; - + const distinctOptions: { sessionToken?: string, useMasterKey: boolean } = { useMasterKey: true }; if (options.hasOwnProperty('sessionToken')) { distinctOptions.sessionToken = options.sessionToken; } @@ -810,10 +845,9 @@ class ParseQuery { * * @returns {Promise} A promise that is resolved with the query completes. */ - aggregate(pipeline: mixed, options?: FullOptions): Promise> { + aggregate(pipeline: any, options?: { sessionToken?: string }): Promise> { options = options || {}; - const aggregateOptions = {}; - aggregateOptions.useMasterKey = true; + const aggregateOptions: { sessionToken?: string, useMasterKey: boolean } = { useMasterKey: true }; if (options.hasOwnProperty('sessionToken')) { aggregateOptions.sessionToken = options.sessionToken; @@ -860,10 +894,10 @@ class ParseQuery { * @returns {Promise} A promise that is resolved with the object when * the query completes. */ - first(options?: FullOptions): Promise { + first(options?: QueryOptions): Promise { options = options || {}; - const findOptions = {}; + const findOptions: QueryOptions = {}; if (options.hasOwnProperty('useMasterKey')) { findOptions.useMasterKey = options.useMasterKey; } @@ -936,7 +970,7 @@ class ParseQuery { * iteration has completed. */ eachBatch( - callback: (objs: Array) => Promise<*>, + callback: (objs: Array) => void, options?: BatchOptions ): Promise { options = options || {}; @@ -974,7 +1008,7 @@ class ParseQuery { query.ascending('objectId'); - const findOptions = {}; + const findOptions: BatchOptions = {}; if (options.hasOwnProperty('useMasterKey')) { findOptions.useMasterKey = options.useMasterKey; } @@ -1050,7 +1084,7 @@ class ParseQuery { * @param {(string|object)} value String or Object of index that should be used when executing query * @returns {Parse.Query} Returns the query, so you can chain this call. */ - hint(value: mixed): ParseQuery { + hint(value: any): ParseQuery { if (typeof value === 'undefined') { delete this._hint; } @@ -1209,16 +1243,16 @@ class ParseQuery { * @param value The value that the Parse.Object must contain. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - equalTo(key: string | { [key: string]: any }, value: ?mixed): ParseQuery { + equalTo(key: string | { [key: string]: any }, value?: any): ParseQuery { if (key && typeof key === 'object') { Object.entries(key).forEach(([k, val]) => this.equalTo(k, val)); return this; } if (typeof value === 'undefined') { - return this.doesNotExist(key); + return this.doesNotExist(key as string); } - this._where[key] = encode(value, false, true); + this._where[key as string] = encode(value, false, true); return this; } @@ -1230,12 +1264,12 @@ class ParseQuery { * @param value The value that must not be equalled. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - notEqualTo(key: string | { [key: string]: any }, value: ?mixed): ParseQuery { + notEqualTo(key: string | { [key: string]: any }, value?: any): ParseQuery { if (key && typeof key === 'object') { Object.entries(key).forEach(([k, val]) => this.notEqualTo(k, val)); return this; } - return this._addCondition(key, '$ne', value); + return this._addCondition(key as string, '$ne', value); } /** @@ -1246,7 +1280,7 @@ class ParseQuery { * @param value The value that provides an upper bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - lessThan(key: string, value: mixed): ParseQuery { + lessThan(key: string, value: any): ParseQuery { return this._addCondition(key, '$lt', value); } @@ -1258,7 +1292,7 @@ class ParseQuery { * @param value The value that provides an lower bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - greaterThan(key: string, value: mixed): ParseQuery { + greaterThan(key: string, value: any): ParseQuery { return this._addCondition(key, '$gt', value); } @@ -1270,7 +1304,7 @@ class ParseQuery { * @param value The value that provides an upper bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - lessThanOrEqualTo(key: string, value: mixed): ParseQuery { + lessThanOrEqualTo(key: string, value: any): ParseQuery { return this._addCondition(key, '$lte', value); } @@ -1282,7 +1316,7 @@ class ParseQuery { * @param {*} value The value that provides an lower bound. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - greaterThanOrEqualTo(key: string, value: mixed): ParseQuery { + greaterThanOrEqualTo(key: string, value: any): ParseQuery { return this._addCondition(key, '$gte', value); } @@ -1294,7 +1328,7 @@ class ParseQuery { * @param {Array<*>} value The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containedIn(key: string, value: Array): ParseQuery { + containedIn(key: string, value: Array): ParseQuery { return this._addCondition(key, '$in', value); } @@ -1306,7 +1340,7 @@ class ParseQuery { * @param {Array<*>} value The values that will not match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - notContainedIn(key: string, value: Array): ParseQuery { + notContainedIn(key: string, value: Array): ParseQuery { return this._addCondition(key, '$nin', value); } @@ -1318,7 +1352,7 @@ class ParseQuery { * @param {Array} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containedBy(key: string, values: Array): ParseQuery { + containedBy(key: string, values: Array): ParseQuery { return this._addCondition(key, '$containedBy', values); } @@ -1330,7 +1364,7 @@ class ParseQuery { * @param {Array} values The values that will match. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - containsAll(key: string, values: Array): ParseQuery { + containsAll(key: string, values: Array): ParseQuery { return this._addCondition(key, '$all', values); } @@ -1385,16 +1419,18 @@ class ParseQuery { * @param {string} modifiers The regular expression mode. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - matches(key: string, regex: RegExp, modifiers: string): ParseQuery { + matches(key: string, regex: RegExp | string, modifiers: string): ParseQuery { this._addCondition(key, '$regex', regex); if (!modifiers) { modifiers = ''; } - if (regex.ignoreCase) { - modifiers += 'i'; - } - if (regex.multiline) { - modifiers += 'm'; + if (typeof regex != 'string') { + if (regex.ignoreCase) { + modifiers += 'i'; + } + if (regex.multiline) { + modifiers += 'm'; + } } if (modifiers.length) { this._addCondition(key, '$options', modifiers); @@ -1516,8 +1552,7 @@ class ParseQuery { * @param {boolean} options.diacriticSensitive A boolean flag to enable or disable diacritic sensitive search. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - fullText(key: string, value: string, options: ?Object): ParseQuery { - options = options || {}; + fullText(key: string, value: string, options: FullTextQueryOptions = {}): ParseQuery { if (!key) { throw new Error('A key is required.'); @@ -1529,22 +1564,22 @@ class ParseQuery { throw new Error('The value being searched for must be a string.'); } - const fullOptions = {}; + const fullOptions: { $term?: string, $language?: string, $caseSensitive?: boolean, $diacriticSensitive?: boolean } = {}; fullOptions.$term = value; for (const option in options) { switch (option) { - case 'language': - fullOptions.$language = options[option]; - break; - case 'caseSensitive': - fullOptions.$caseSensitive = options[option]; - break; - case 'diacriticSensitive': - fullOptions.$diacriticSensitive = options[option]; - break; - default: - throw new Error(`Unknown option: ${option}`); + case 'language': + fullOptions.$language = options[option]; + break; + case 'caseSensitive': + fullOptions.$caseSensitive = options[option]; + break; + case 'diacriticSensitive': + fullOptions.$diacriticSensitive = options[option]; + break; + default: + throw new Error(`Unknown option: ${option}`); } } @@ -2099,9 +2134,10 @@ class ParseQuery { this._xhrRequest.task._aborted = true; this._xhrRequest.task.abort(); this._xhrRequest.task = null; - this._xhrRequest.onchange = () => {}; + this._xhrRequest.onchange = () => { }; return this; } + // TODO: Typescript.. How does this work? Does this even make sense? return (this._xhrRequest.onchange = () => this.cancel()); } @@ -2114,12 +2150,12 @@ class ParseQuery { } const DefaultController = { - find(className: string, params: QueryJSON, options: RequestOptions): Promise> { + find(className: string, params: QueryJSON, options: RequestOptions): Promise<{ results: Array }> { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'classes/' + className, params, options); }, - aggregate(className: string, params: any, options: RequestOptions): Promise> { + aggregate(className: string, params: any, options: RequestOptions): Promise<{ results: Array }> { const RESTController = CoreManager.getRESTController(); return RESTController.request('GET', 'aggregate/' + className, params, options); diff --git a/src/ParseUser.js b/src/ParseUser.ts similarity index 92% rename from src/ParseUser.js rename to src/ParseUser.ts index 8ba9ba8c0..a38f04cfd 100644 --- a/src/ParseUser.js +++ b/src/ParseUser.ts @@ -12,14 +12,27 @@ import Storage from './Storage'; import type { AttributeMap } from './ObjectStateMutations'; import type { RequestOptions, FullOptions } from './RESTController'; -export type AuthData = ?{ [key: string]: mixed }; +export type AuthData = { [key: string]: any }; + +type AuthProviderType = { + authenticate?(options: { + error?: (provider: AuthProviderType, error: string) => void, + success?: (provider: AuthProviderType, result: AuthData) => void, + }): void, + + restoreAuthentication(authData: any): boolean; + /** Returns the AuthType of this provider */ + getAuthType(): string; + deauthenticate?(): void; +}; + const CURRENT_USER_KEY = 'currentUser'; let canUseCurrentUser = !CoreManager.get('IS_NODE'); let currentUserCacheMatchesDisk = false; let currentUserCache = null; -const authProviders = {}; +const authProviders: { [key: string]: AuthProviderType } = {}; /** *

    A Parse.User object is a local representation of a user persisted to the @@ -35,7 +48,7 @@ class ParseUser extends ParseObject { /** * @param {object} attributes The initial set of data to store in the user. */ - constructor(attributes: ?AttributeMap) { + constructor(attributes?: AttributeMap) { super('_User'); if (attributes && typeof attributes === 'object') { if (!this.set(attributes || {})) { @@ -54,7 +67,7 @@ class ParseUser extends ParseObject { _upgradeToRevocableSession(options: RequestOptions): Promise { options = options || {}; - const upgradeOptions = {}; + const upgradeOptions: RequestOptions = {}; if (options.hasOwnProperty('useMasterKey')) { upgradeOptions.useMasterKey = options.useMasterKey; } @@ -79,12 +92,12 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user is linked */ linkWith( - provider: any, + provider: AuthProviderType, options: { authData?: AuthData }, - saveOpts?: FullOptions = {} + saveOpts: FullOptions = {} ): Promise { saveOpts.sessionToken = saveOpts.sessionToken || this.getSessionToken() || ''; - let authType; + let authType: string; if (typeof provider === 'string') { authType = provider; if (authProviders[provider]) { @@ -123,7 +136,7 @@ class ParseUser extends ParseObject { return new Promise((resolve, reject) => { provider.authenticate({ success: (provider, result) => { - const opts = {}; + const opts: { authData?: AuthData } = {}; opts.authData = result; this.linkWith(provider, opts, saveOpts).then( () => { @@ -152,7 +165,7 @@ class ParseUser extends ParseObject { _linkWith( provider: any, options: { authData?: AuthData }, - saveOpts?: FullOptions = {} + saveOpts: FullOptions = {} ): Promise { return this.linkWith(provider, options, saveOpts); } @@ -163,7 +176,7 @@ class ParseUser extends ParseObject { * * @param provider */ - _synchronizeAuthData(provider: string) { + _synchronizeAuthData(provider: string | AuthProviderType) { if (!this.isCurrent() || !provider) { return; } @@ -336,7 +349,7 @@ class ParseUser extends ParseObject { * * @returns {string} */ - getUsername(): ?string { + getUsername(): string | null { const username = this.get('username'); if (username == null || typeof username === 'string') { return username; @@ -368,7 +381,7 @@ class ParseUser extends ParseObject { * * @returns {string} User's Email */ - getEmail(): ?string { + getEmail(): string | null { const email = this.get('email'); if (email == null || typeof email === 'string') { return email; @@ -393,7 +406,7 @@ class ParseUser extends ParseObject { * * @returns {string} the session token, or undefined */ - getSessionToken(): ?string { + getSessionToken(): string | null { const token = this.get('sessionToken'); if (token == null || typeof token === 'string') { return token; @@ -424,10 +437,10 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled when the signup * finishes. */ - signUp(attrs: AttributeMap, options?: FullOptions): Promise { + signUp(attrs: AttributeMap, options?: FullOptions & { context?: AttributeMap }): Promise { options = options || {}; - const signupOptions = {}; + const signupOptions: FullOptions & { context?: AttributeMap } = {}; if (options.hasOwnProperty('useMasterKey')) { signupOptions.useMasterKey = options.useMasterKey; } @@ -456,10 +469,9 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with the user when * the login is complete. */ - logIn(options?: FullOptions): Promise { - options = options || {}; + logIn(options: FullOptions & { context?: AttributeMap } = {}): Promise { - const loginOptions = { usePost: true }; + const loginOptions: { usePost: boolean, context?: AttributeMap } & FullOptions = { usePost: true }; if (options.hasOwnProperty('useMasterKey')) { loginOptions.useMasterKey = options.useMasterKey; } @@ -486,11 +498,11 @@ class ParseUser extends ParseObject { * @param {...any} args * @returns {Promise} */ - async save(...args: Array): Promise { + async save(...args: Array): Promise { await super.save.apply(this, args); const current = await this.isCurrentAsync(); if (current) { - return CoreManager.getUserController().updateUserOnDisk(this); + return CoreManager.getUserController().updateUserOnDisk(this) as Promise; } return this; } @@ -500,9 +512,9 @@ class ParseUser extends ParseObject { * the current user when it is destroyed * * @param {...any} args - * @returns {Parse.User} + * @returns {Parse.User|void} seems to depend on implementation (default = void). */ - async destroy(...args: Array): Promise { + async destroy(...args: Array): Promise { await super.destroy.apply(this, args); const current = await this.isCurrentAsync(); if (current) { @@ -606,7 +618,7 @@ class ParseUser extends ParseObject { * @static * @returns {Parse.Object} The currently logged in Parse.User. */ - static current(): ?ParseUser { + static current(): ParseUser | null { if (!canUseCurrentUser) { return null; } @@ -621,7 +633,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A Promise that is resolved with the currently * logged in Parse User */ - static currentAsync(): Promise { + static currentAsync(): Promise { if (!canUseCurrentUser) { return Promise.resolve(null); } @@ -758,7 +770,7 @@ class ParseUser extends ParseObject { * @static * @returns {Promise} A promise that is fulfilled with the user is fetched. */ - static me(sessionToken: string, options?: RequestOptions = {}) { + static me(sessionToken: string, options: RequestOptions = {}) { const controller = CoreManager.getUserController(); const meOptions: RequestOptions = { sessionToken: sessionToken, @@ -833,7 +845,7 @@ class ParseUser extends ParseObject { static requestPasswordReset(email: string, options?: RequestOptions) { options = options || {}; - const requestOptions = {}; + const requestOptions: { useMasterKey?: boolean } = {}; if (options.hasOwnProperty('useMasterKey')) { requestOptions.useMasterKey = options.useMasterKey; } @@ -854,7 +866,7 @@ class ParseUser extends ParseObject { static requestEmailVerification(email: string, options?: RequestOptions) { options = options || {}; - const requestOptions = {}; + const requestOptions: RequestOptions = {}; if (options.hasOwnProperty('useMasterKey')) { requestOptions.useMasterKey = options.useMasterKey; } @@ -873,7 +885,7 @@ class ParseUser extends ParseObject { * @returns {Promise} A promise that is fulfilled with a user * when the password is correct. */ - static verifyPassword(username: string, password: string, options?: RequestOptions) { + static verifyPassword(username: string, password: string, options?: RequestOptions): Promise { if (typeof username !== 'string') { return Promise.reject(new ParseError(ParseError.OTHER_CAUSE, 'Username must be a string.')); } @@ -884,7 +896,7 @@ class ParseUser extends ParseObject { options = options || {}; - const verificationOption = {}; + const verificationOption: RequestOptions = {}; if (options.hasOwnProperty('useMasterKey')) { verificationOption.useMasterKey = options.useMasterKey; } @@ -1032,7 +1044,7 @@ const DefaultController = { return DefaultController.updateUserOnDisk(user); }, - currentUser(): ?ParseUser { + currentUser(): ParseUser | null { if (currentUserCache) { return currentUserCache; } @@ -1042,7 +1054,7 @@ const DefaultController = { if (Storage.async()) { throw new Error( 'Cannot call currentUser() when using a platform with an async ' + - 'storage system. Call currentUserAsync() instead.' + 'storage system. Call currentUserAsync() instead.' ); } const path = Storage.generatePath(CURRENT_USER_KEY); @@ -1056,27 +1068,27 @@ const DefaultController = { const crypto = CoreManager.getCryptoController(); userData = crypto.decrypt(userData, CoreManager.get('ENCRYPTED_KEY')); } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; + const userDataObj = JSON.parse(userData); + if (!userDataObj.className) { + userDataObj.className = '_User'; } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; + if (userDataObj._id) { + if (userDataObj.objectId !== userDataObj._id) { + userDataObj.objectId = userDataObj._id; } - delete userData._id; + delete userDataObj._id; } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; + if (userDataObj._sessionToken) { + userDataObj.sessionToken = userDataObj._sessionToken; + delete userDataObj._sessionToken; } - const current = ParseObject.fromJSON(userData); + const current = ParseObject.fromJSON(userDataObj) as ParseUser; currentUserCache = current; current._synchronizeAllAuthData(); return current; }, - currentUserAsync(): Promise { + currentUserAsync(): Promise { if (currentUserCache) { return Promise.resolve(currentUserCache); } @@ -1094,21 +1106,21 @@ const DefaultController = { const crypto = CoreManager.getCryptoController(); userData = crypto.decrypt(userData.toString(), CoreManager.get('ENCRYPTED_KEY')); } - userData = JSON.parse(userData); - if (!userData.className) { - userData.className = '_User'; + const userDataObj = JSON.parse(userData); + if (!userDataObj.className) { + userDataObj.className = '_User'; } - if (userData._id) { - if (userData.objectId !== userData._id) { - userData.objectId = userData._id; + if (userDataObj._id) { + if (userDataObj.objectId !== userDataObj._id) { + userDataObj.objectId = userDataObj._id; } - delete userData._id; + delete userDataObj._id; } - if (userData._sessionToken) { - userData.sessionToken = userData._sessionToken; - delete userData._sessionToken; + if (userDataObj._sessionToken) { + userDataObj.sessionToken = userDataObj._sessionToken; + delete userDataObj._sessionToken; } - const current = ParseObject.fromJSON(userData); + const current = ParseObject.fromJSON(userDataObj) as ParseUser; currentUserCache = current; current._synchronizeAllAuthData(); return Promise.resolve(current); @@ -1206,7 +1218,7 @@ const DefaultController = { }); }, - logOut(options: RequestOptions): Promise { + logOut(options: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); if (options.sessionToken) { return RESTController.request('POST', 'logout', {}, options); @@ -1258,7 +1270,7 @@ const DefaultController = { return Promise.resolve(user); }, - linkWith(user: ParseUser, authData: AuthData, options: FullOptions) { + linkWith(user: ParseUser, authData: AuthData, options?: FullOptions) { return user.save({ authData }, options).then(() => { if (canUseCurrentUser) { return DefaultController.setCurrentUser(user); diff --git a/src/Push.js b/src/Push.ts similarity index 89% rename from src/Push.js rename to src/Push.ts index a565396be..a38c35dcd 100644 --- a/src/Push.js +++ b/src/Push.ts @@ -3,6 +3,7 @@ */ import CoreManager from './CoreManager'; +import ParseObject from './ParseObject'; import ParseQuery from './ParseQuery'; import type { WhereClause } from './ParseQuery'; @@ -49,9 +50,9 @@ export type PushData = { * be used for this request. * * @returns {Promise} A promise that is fulfilled when the push request - * completes. + * completes., returns `pushStatusId` */ -export function send(data: PushData, options?: FullOptions = {}): Promise { +export function send(data: PushData, options: FullOptions = {}): Promise { if (data.where && data.where instanceof ParseQuery) { data.where = data.where.toJSON().where; } @@ -89,7 +90,7 @@ export function send(data: PushData, options?: FullOptions = {}): Promise { * * @returns {Parse.Object} Status of Push. */ -export function getPushStatus(pushStatusId: string, options?: FullOptions = {}): Promise { +export function getPushStatus(pushStatusId: string, options: FullOptions = {}): Promise { const pushOptions = { useMasterKey: true }; if (options.hasOwnProperty('useMasterKey')) { pushOptions.useMasterKey = options.useMasterKey; @@ -100,8 +101,8 @@ export function getPushStatus(pushStatusId: string, options?: FullOptions = {}): const DefaultController = { async send(data: PushData, options?: FullOptions) { - options.returnStatus = true; - const response = await CoreManager.getRESTController().request('POST', 'push', data, options); + const myOptions = { ...options, returnStatus: true }; + const response = await CoreManager.getRESTController().request('POST', 'push', data, myOptions); return response._headers?.['X-Parse-Push-Status-Id']; }, }; From 1b3ba9d3395cd44287634ae75a36c4965b8fc813 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Sun, 29 Oct 2023 22:27:32 +0700 Subject: [PATCH 11/27] even more typings --- src/CoreManager.ts | 73 ++++++++++++++++++- ...{EventuallyQueue.js => EventuallyQueue.ts} | 71 +++++++++--------- ...seInstallation.js => ParseInstallation.ts} | 2 +- src/ParseObject.ts | 2 +- src/ParseQuery.ts | 4 +- ...efault.js => StorageController.default.ts} | 2 +- ...e.js => StorageController.react-native.ts} | 34 ++++----- ...{unsavedChildren.js => unsavedChildren.ts} | 2 +- 8 files changed, 128 insertions(+), 62 deletions(-) rename src/{EventuallyQueue.js => EventuallyQueue.ts} (88%) rename src/{ParseInstallation.js => ParseInstallation.ts} (91%) rename src/{StorageController.default.js => StorageController.default.ts} (93%) rename src/{StorageController.react-native.js => StorageController.react-native.ts} (52%) rename src/{unsavedChildren.js => unsavedChildren.ts} (96%) diff --git a/src/CoreManager.ts b/src/CoreManager.ts index 57c6877b4..ecb4a7867 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -75,7 +75,7 @@ type QueryController = { aggregate(className: string, params: any, options: RequestOptions): Promise<{ results?: Array }>; }; type RESTController = { - request: (method: string, path: string, data: any, options?: RequestOptions) => Promise, + request: (method: string, path: string, data?: any, options?: RequestOptions) => Promise, ajax: (method: string, url: string, data: any, headers?: any, options?: FullOptions) => Promise, handleError: (err?: any) => void, }; @@ -154,7 +154,71 @@ type LiveQueryControllerType = { getDefaultLiveQueryClient(): Promise; _clearCachedDefaultClient(): void; } - +/** Based on https://github.com/react-native-async-storage/async-storage/blob/main/packages/default-storage-backend/src/types.ts */ +type AsyncStorageType = { + /** Fetches an item for a `key` and invokes a callback upon completion. */ + getItem: ( + key: string, + callback?: (error?: Error | null, result?: string | null) => void + ) => Promise; + /** Sets the value for a `key` and invokes a callback upon completion. */ + setItem: (key: string, value: string, callback?: (error?: Error | null) => void) => Promise; + /** Removes an item for a `key` and invokes a callback upon completion. */ + removeItem: (key: string, callback?: (error?: Error | null) => void) => Promise; + /** Merges an existing `key` value with an input value, assuming both values are stringified JSON. */ + mergeItem: (key: string, value: string, callback?: (error?: Error | null) => void) => Promise; + /** + * Erases *all* `AsyncStorage` for all clients, libraries, etc. You probably + * don't want to call this; use `removeItem` or `multiRemove` to clear only + * your app's keys. + */ + clear: (callback?: (error?: Error | null) => void) => Promise; + /** Gets *all* keys known to your app; for all callers, libraries, etc. */ + getAllKeys: ( + callback?: (error?: Error | null, result?: readonly string[] | null) => void + ) => Promise; + /** + * This allows you to batch the fetching of items given an array of `key` + * inputs. Your callback will be invoked with an array of corresponding + * key-value pairs found. + */ + multiGet: ( + keys: readonly string[], + callback?: (errors?: readonly (Error | null)[] | null, result?: readonly [string, string][]) => void + ) => Promise; + + /** + * Use this as a batch operation for storing multiple key-value pairs. When + * the operation completes you'll get a single callback with any errors. + * + * See https://react-native-async-storage.github.io/async-storage/docs/api#multiset + */ + multiSet: ( + keyValuePairs: [string, string][], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + + /** + * Call this to batch the deletion of all keys in the `keys` array. + * + * See https://react-native-async-storage.github.io/async-storage/docs/api#multiremove + */ + multiRemove: ( + keys: readonly string[], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; + + /** + * Batch operation to merge in existing and new values for a given set of + * keys. This assumes that the values are stringified JSON. + * + * See https://react-native-async-storage.github.io/async-storage/docs/api#multimerge + */ + multiMerge: ( + keyValuePairs: [string, string][], + callback?: (errors?: readonly (Error | null)[] | null) => void + ) => Promise; +}; export type WebSocketController = { onopen: () => void, onmessage: (message: any) => void, @@ -181,7 +245,8 @@ type Config = { UserController?: UserController, HooksController?: HooksController, WebSocketController?: new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController, - LiveQueryController?: LiveQueryControllerType + LiveQueryController?: LiveQueryControllerType, + AsyncStorage?: AsyncStorageType }; const config: Config & { [key: string]: any } = { @@ -442,7 +507,7 @@ const CoreManager = { return config['StorageController']; }, - setAsyncStorage(storage: any) { + setAsyncStorage(storage: AsyncStorageType) { config['AsyncStorage'] = storage; }, diff --git a/src/EventuallyQueue.js b/src/EventuallyQueue.ts similarity index 88% rename from src/EventuallyQueue.js rename to src/EventuallyQueue.ts index 88df1d3bd..53f9f9782 100644 --- a/src/EventuallyQueue.js +++ b/src/EventuallyQueue.ts @@ -27,9 +27,9 @@ type QueueObject = { type Queue = Array; const QUEUE_KEY = 'Parse/Eventually/Queue'; -let queueCache = []; +let queueCache: QueueObject[] = []; let dirtyCache = true; -let polling = undefined; +let polling: ReturnType | undefined = undefined; /** * Provides utility functions to queue objects that will be @@ -50,7 +50,7 @@ const EventuallyQueue = { * @static * @see Parse.Object#saveEventually */ - save(object: ParseObject, serverOptions: SaveOptions = {}): Promise { + save(object: ParseObject, serverOptions: SaveOptions = {}): Promise { return this.enqueue('save', object, serverOptions); }, @@ -65,7 +65,7 @@ const EventuallyQueue = { * @static * @see Parse.Object#destroyEventually */ - destroy(object: ParseObject, serverOptions: RequestOptions = {}): Promise { + destroy(object: ParseObject, serverOptions: RequestOptions = {}): Promise { return this.enqueue('destroy', object, serverOptions); }, @@ -99,7 +99,7 @@ const EventuallyQueue = { action: string, object: ParseObject, serverOptions: SaveOptions | RequestOptions - ): Promise { + ): Promise { const queueData = await this.getQueue(); const queueId = this.generateQueueId(action, object); @@ -127,7 +127,7 @@ const EventuallyQueue = { return this.setQueue(queueData); }, - store(data) { + store(data: QueueObject[]) { return Storage.setItemAsync(QUEUE_KEY, JSON.stringify(data)); }, @@ -143,7 +143,7 @@ const EventuallyQueue = { * @returns {Promise} * @static */ - async getQueue(): Promise { + async getQueue(): Promise { if (dirtyCache) { queueCache = JSON.parse((await this.load()) || '[]'); dirtyCache = false; @@ -189,7 +189,7 @@ const EventuallyQueue = { * @returns {Promise} A promise that is fulfilled when queue is cleared. * @static */ - clear(): Promise { + clear(): Promise { queueCache = []; return this.store([]); }, @@ -215,7 +215,7 @@ const EventuallyQueue = { * @returns {number} * @static */ - async length(): number { + async length(): Promise { const queueData = await this.getQueue(); return queueData.length; }, @@ -264,33 +264,33 @@ const EventuallyQueue = { return this.remove(queueObject.queueId); } switch (queueObject.action) { - case 'save': - // Queued update was overwritten by other request. Do not save - if ( - typeof object.updatedAt !== 'undefined' && - object.updatedAt > new Date(queueObject.object.createdAt) - ) { - return this.remove(queueObject.queueId); - } - try { - await object.save(queueObject.object, queueObject.serverOptions); - await this.remove(queueObject.queueId); - } catch (e) { - if (e.code !== ParseError.CONNECTION_FAILED) { + case 'save': + // Queued update was overwritten by other request. Do not save + if ( + typeof object.updatedAt !== 'undefined' && + object.updatedAt > new Date(queueObject.object.createdAt!) + ) { + return this.remove(queueObject.queueId); + } + try { + await object.save(queueObject.object, queueObject.serverOptions); await this.remove(queueObject.queueId); + } catch (e) { + if (e.code !== ParseError.CONNECTION_FAILED) { + await this.remove(queueObject.queueId); + } } - } - break; - case 'destroy': - try { - await object.destroy(queueObject.serverOptions); - await this.remove(queueObject.queueId); - } catch (e) { - if (e.code !== ParseError.CONNECTION_FAILED) { + break; + case 'destroy': + try { + await object.destroy(queueObject.serverOptions); await this.remove(queueObject.queueId); + } catch (e) { + if (e.code !== ParseError.CONNECTION_FAILED) { + await this.remove(queueObject.queueId); + } } - } - break; + break; } }, @@ -344,16 +344,17 @@ const EventuallyQueue = { return !!polling; }, + /** Used only for haxx debug */ _setPolling(flag: boolean) { - polling = flag; + polling = flag as any; }, process: { - create(ObjectType, queueObject) { + create(ObjectType: typeof ParseObject, queueObject) { const object = new ObjectType(); return EventuallyQueue.sendQueueCallback(object, queueObject); }, - async byId(ObjectType, queueObject) { + async byId(ObjectType: string | ParseObject | (typeof ParseObject), queueObject) { const { sessionToken } = queueObject.serverOptions; const query = new ParseQuery(ObjectType); query.equalTo('objectId', queueObject.id); diff --git a/src/ParseInstallation.js b/src/ParseInstallation.ts similarity index 91% rename from src/ParseInstallation.js rename to src/ParseInstallation.ts index 380b5c8a9..c624aa27f 100644 --- a/src/ParseInstallation.js +++ b/src/ParseInstallation.ts @@ -7,7 +7,7 @@ import ParseObject from './ParseObject'; import type { AttributeMap } from './ObjectStateMutations'; export default class Installation extends ParseObject { - constructor(attributes: ?AttributeMap) { + constructor(attributes?: AttributeMap) { super('_Installation'); if (attributes && typeof attributes === 'object') { if (!this.set(attributes || {})) { diff --git a/src/ParseObject.ts b/src/ParseObject.ts index 48b0a0012..0caf939ab 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -1951,7 +1951,7 @@ class ParseObject { * this method. * @returns {Parse.Object} A new subclass of Parse.Object. */ - static extend(className: any, protoProps: any, classProps: any) { + static extend(className: any, protoProps?: any, classProps?: any) { if (typeof className !== 'string') { if (className && typeof className.className === 'string') { return ParseObject.extend(className.className, className, protoProps); diff --git a/src/ParseQuery.ts b/src/ParseQuery.ts index b1fb02305..f9a692dce 100644 --- a/src/ParseQuery.ts +++ b/src/ParseQuery.ts @@ -283,7 +283,7 @@ class ParseQuery { /** * @param {(string | Parse.Object)} objectClass An instance of a subclass of Parse.Object, or a Parse className string. */ - constructor(objectClass: string | ParseObject) { + constructor(objectClass: string | ParseObject | (typeof ParseObject)) { if (typeof objectClass === 'string') { if (objectClass === 'User' && CoreManager.get('PERFORM_USER_REWRITE')) { this.className = '_User'; @@ -295,7 +295,7 @@ class ParseQuery { } else if (typeof objectClass === 'function') { const objectClz = (objectClass) as typeof ParseObject; if (typeof objectClz.className === 'string') { - this.className = objectClass; + this.className = objectClz.className; } else { const obj = new objectClz(); this.className = obj.className; diff --git a/src/StorageController.default.js b/src/StorageController.default.ts similarity index 93% rename from src/StorageController.default.js rename to src/StorageController.default.ts index cb21dd54f..8e0bdd7fb 100644 --- a/src/StorageController.default.js +++ b/src/StorageController.default.ts @@ -8,7 +8,7 @@ const memMap = {}; const StorageController = { async: 0, - getItem(path: string): ?string { + getItem(path: string): string | null { if (memMap.hasOwnProperty(path)) { return memMap[path]; } diff --git a/src/StorageController.react-native.js b/src/StorageController.react-native.ts similarity index 52% rename from src/StorageController.react-native.js rename to src/StorageController.react-native.ts index e3ee63dce..c80844ebb 100644 --- a/src/StorageController.react-native.js +++ b/src/StorageController.react-native.ts @@ -7,33 +7,33 @@ import CoreManager from './CoreManager'; const StorageController = { async: 1, - getItemAsync(path: string): Promise { + getItemAsync(path: string): Promise { return new Promise((resolve, reject) => { - CoreManager.getAsyncStorage().getItem(path, (err, value) => { + CoreManager.getAsyncStorage()!.getItem(path, (err, value) => { if (err) { reject(err); } else { - resolve(value); + resolve(value || null); } }); }); }, - setItemAsync(path: string, value: string): Promise { + setItemAsync(path: string, value: string): Promise { return new Promise((resolve, reject) => { - CoreManager.getAsyncStorage().setItem(path, value, (err, value) => { + CoreManager.getAsyncStorage()!.setItem(path, value, (err) => { if (err) { reject(err); } else { - resolve(value); + resolve(); } }); }); }, - removeItemAsync(path: string): Promise { + removeItemAsync(path: string): Promise { return new Promise((resolve, reject) => { - CoreManager.getAsyncStorage().removeItem(path, err => { + CoreManager.getAsyncStorage()!.removeItem(path, err => { if (err) { reject(err); } else { @@ -43,33 +43,33 @@ const StorageController = { }); }, - getAllKeysAsync(): Promise { + getAllKeysAsync(): Promise { return new Promise((resolve, reject) => { - CoreManager.getAsyncStorage().getAllKeys((err, keys) => { + CoreManager.getAsyncStorage()!.getAllKeys((err, keys) => { if (err) { reject(err); } else { - resolve(keys); + resolve(keys || null); } }); }); }, - multiGet(keys: Array): Promise>> { + multiGet(keys: Array): Promise { return new Promise((resolve, reject) => { - CoreManager.getAsyncStorage().multiGet(keys, (err, result) => { + CoreManager.getAsyncStorage()!.multiGet(keys, (err, result) => { if (err) { reject(err); } else { - resolve(result); + resolve(result || null); } }); }); }, - multiRemove(keys: Array): Promise { + multiRemove(keys: Array): Promise> { return new Promise((resolve, reject) => { - CoreManager.getAsyncStorage().multiRemove(keys, err => { + CoreManager.getAsyncStorage()!.multiRemove(keys, err => { if (err) { reject(err); } else { @@ -80,7 +80,7 @@ const StorageController = { }, clear() { - return CoreManager.getAsyncStorage().clear(); + return CoreManager.getAsyncStorage()!.clear(); }, }; diff --git a/src/unsavedChildren.js b/src/unsavedChildren.ts similarity index 96% rename from src/unsavedChildren.js rename to src/unsavedChildren.ts index 088bd6084..1411f0d1c 100644 --- a/src/unsavedChildren.js +++ b/src/unsavedChildren.ts @@ -45,7 +45,7 @@ export default function unsavedChildren( } function traverse( - obj: ParseObject, + obj: ParseObject | ParseFile | ParseRelation | Array, encountered: EncounterMap, shouldThrow: boolean, allowDeepUnsaved: boolean From 9839439b24cf1c3794c902ca0650b4ec03b56e90 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 04:19:26 +0700 Subject: [PATCH 12/27] more simple files --- src/{Cloud.js => Cloud.ts} | 10 +++++----- src/CoreManager.ts | 9 +++++---- ...allationController.js => InstallationController.ts} | 6 +++--- src/ParseGeoPoint.ts | 2 ++ src/ParseObject.ts | 5 +++-- src/Storage.ts | 2 +- 6 files changed, 19 insertions(+), 15 deletions(-) rename src/{Cloud.js => Cloud.ts} (92%) rename src/{InstallationController.js => InstallationController.ts} (84%) diff --git a/src/Cloud.js b/src/Cloud.ts similarity index 92% rename from src/Cloud.js rename to src/Cloud.ts index 0d218843c..7dcf76a00 100644 --- a/src/Cloud.js +++ b/src/Cloud.ts @@ -33,14 +33,14 @@ import type { RequestOptions } from './RESTController'; * @returns {Promise} A promise that will be resolved with the result * of the function. */ -export function run(name: string, data: mixed, options: RequestOptions): Promise { +export function run(name: string, data: any, options: RequestOptions): Promise { options = options || {}; if (typeof name !== 'string' || name.length === 0) { throw new TypeError('Cloud function name must be a string.'); } - const requestOptions = {}; + const requestOptions: RequestOptions = {}; if (options.useMasterKey) { requestOptions.useMasterKey = options.useMasterKey; } @@ -82,7 +82,7 @@ export function getJobsData(): Promise { * @returns {Promise} A promise that will be resolved with the jobStatusId * of the job. */ -export function startJob(name: string, data: mixed): Promise { +export function startJob(name: string, data: any): Promise { if (typeof name !== 'string' || name.length === 0) { throw new TypeError('Cloud job name must be a string.'); } @@ -106,7 +106,7 @@ export function getJobStatus(jobStatusId: string): Promise { } const DefaultController = { - run(name, data, options: RequestOptions) { + run(name: string, data: any, options: RequestOptions) { const RESTController = CoreManager.getRESTController(); const payload = encode(data, true); @@ -131,7 +131,7 @@ const DefaultController = { return RESTController.request('GET', 'cloud_code/jobs/data', null, options); }, - async startJob(name, data, options: RequestOptions) { + async startJob(name: string, data: any, options: RequestOptions): Promise { const RESTController = CoreManager.getRESTController(); const payload = encode(data, true); diff --git a/src/CoreManager.ts b/src/CoreManager.ts index ecb4a7867..f4cd25f1c 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -14,12 +14,13 @@ import type ParseConfig from './ParseConfig'; import type LiveQueryClient from './LiveQueryClient'; type AnalyticsController = { - track: (name: string, dimensions: { [key: string]: string }) => Promise, + track: (name: string, dimensions: { [key: string]: string }) => Promise, }; type CloudController = { - run: (name: string, data: any, options: RequestOptions) => Promise, - getJobsData: (options: RequestOptions) => Promise, - startJob: (name: string, data: any, options: RequestOptions) => Promise, + run: (name: string, data: any, options: RequestOptions) => Promise, + getJobsData: (options: RequestOptions) => Promise, + /** Returns promise which resolves with JobStatusId of the job */ + startJob: (name: string, data: any, options: RequestOptions) => Promise, }; type ConfigController = { current: () => Promise, diff --git a/src/InstallationController.js b/src/InstallationController.ts similarity index 84% rename from src/InstallationController.js rename to src/InstallationController.ts index 41d865d10..410b9b1b5 100644 --- a/src/InstallationController.js +++ b/src/InstallationController.ts @@ -5,7 +5,7 @@ import Storage from './Storage'; const uuidv4 = require('./uuid'); -let iidCache = null; +let iidCache: string|null = null; const InstallationController = { currentInstallationId(): Promise { @@ -16,9 +16,9 @@ const InstallationController = { return Storage.getItemAsync(path).then(iid => { if (!iid) { iid = uuidv4(); - return Storage.setItemAsync(path, iid).then(() => { + return Storage.setItemAsync(path, iid!).then(() => { iidCache = iid; - return iid; + return iid!; }); } iidCache = iid; diff --git a/src/ParseGeoPoint.ts b/src/ParseGeoPoint.ts index 66ec076fc..95cdd8e95 100644 --- a/src/ParseGeoPoint.ts +++ b/src/ParseGeoPoint.ts @@ -187,6 +187,8 @@ class ParseGeoPoint { * @returns {Parse.GeoPoint} User's current location */ // TODO: Typescript; How does this thing work? + // Seems we're using the power of Javascript by returning a value from a synchronous callback, so the value ends up correct somehow in tests? + // Should this be `async` instead for safety? Since it's a callback pattern static current() { return navigator.geolocation.getCurrentPosition(location => { return new ParseGeoPoint(location.coords.latitude, location.coords.longitude); diff --git a/src/ParseObject.ts b/src/ParseObject.ts index 0caf939ab..44fae9c9e 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -2415,8 +2415,9 @@ const DefaultController = { let unsaved = target.concat(); for (let i = 0; i < target.length; i++) { - if (target[i] instanceof ParseObject) { - unsaved = unsaved.concat(unsavedChildren(target[i], true)); + const target_i = target[i]; + if (target_i instanceof ParseObject) { + unsaved = unsaved.concat(unsavedChildren(target_i, true)); } } unsaved = unique(unsaved); diff --git a/src/Storage.ts b/src/Storage.ts index 0af496743..bcc47a990 100644 --- a/src/Storage.ts +++ b/src/Storage.ts @@ -34,7 +34,7 @@ const Storage = { return controller.setItem(path, value); }, - setItemAsync(path: string, value: string): Promise { + setItemAsync(path: string, value: string | null): Promise { const controller = CoreManager.getStorageController(); if (controller.async === 1) { return controller.setItemAsync(path, value); From b2c27dd0163041459e236dfc7af6d3855db62e63 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 04:57:19 +0700 Subject: [PATCH 13/27] comments --- src/ObjectStateMutations.ts | 9 ++++++++- src/ParseACL.ts | 10 ++++++++++ src/ParseCLP.ts | 2 ++ src/ParseFile.ts | 5 ++--- src/ParseObject.ts | 4 ++-- src/ParseRole.ts | 2 +- src/decode.ts | 2 +- src/encode.ts | 2 +- src/uuid.ts | 1 + 9 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/ObjectStateMutations.ts b/src/ObjectStateMutations.ts index 8e4003358..04e8eeecb 100644 --- a/src/ObjectStateMutations.ts +++ b/src/ObjectStateMutations.ts @@ -147,7 +147,14 @@ export function estimateAttributes( return data; } -function nestedSet(obj, key, value) { +/** + * Allows setting properties/variables deep in an object. + * @param obj The object to assign the value to + * @param key The key to assign. If it's in a deeper path, then use dot notation (`prop1.prop2.prop3`) + * Note that intermediate object(s) in the nested path are automatically created if they don't exist. + * @param value The value to assign. If it's an `undefined` then the key is deleted. + */ +function nestedSet(obj: AttributeMap, key: string, value: any) { const path = key.split('.'); for (let i = 0; i < path.length - 1; i++) { if (!(path[i] in obj)) { diff --git a/src/ParseACL.ts b/src/ParseACL.ts index daf9d0ac8..c1b0bbad5 100644 --- a/src/ParseACL.ts +++ b/src/ParseACL.ts @@ -101,6 +101,7 @@ class ParseACL { _setAccess(accessType: string, userId: ParseUser | ParseRole | string, allowed: boolean) { if (userId instanceof ParseUser) { + // We would expect the ParseUser to have an ID; we don't have Users without IDs, right? userId = userId.id!; } else if (userId instanceof ParseRole) { const name = userId.getName(); @@ -138,6 +139,7 @@ class ParseACL { _getAccess(accessType: string, userId: ParseUser | ParseRole | string): boolean { if (userId instanceof ParseUser) { + // We would expect the ParseUser to have an ID; we don't have Users without IDs, right? userId = userId.id!; if (!userId) { throw new Error('Cannot get access for a ParseUser without an ID'); @@ -250,6 +252,8 @@ class ParseACL { getRoleReadAccess(role: ParseRole | string): boolean { if (role instanceof ParseRole) { // Normalize to the String name + // A forced cast here is likely harmless since we force check + // `typeof role === 'string'` after this. role = role.getName()!; } if (typeof role !== 'string') { @@ -270,6 +274,8 @@ class ParseACL { getRoleWriteAccess(role: ParseRole | string): boolean { if (role instanceof ParseRole) { // Normalize to the String name + // A forced cast here is likely harmless since we force check + // `typeof role === 'string'` after this. role = role.getName()!; } if (typeof role !== 'string') { @@ -289,6 +295,8 @@ class ParseACL { setRoleReadAccess(role: ParseRole | string, allowed: boolean) { if (role instanceof ParseRole) { // Normalize to the String name + // A forced cast here is likely harmless since we force check + // `typeof role === 'string'` after this. role = role.getName()!; } if (typeof role !== 'string') { @@ -308,6 +316,8 @@ class ParseACL { setRoleWriteAccess(role: ParseRole | string, allowed: boolean) { if (role instanceof ParseRole) { // Normalize to the String name + // A forced cast here is likely harmless since we force check + // `typeof role === 'string'` after this. role = role.getName()!; } if (typeof role !== 'string') { diff --git a/src/ParseCLP.ts b/src/ParseCLP.ts index c9547436f..20e2984d7 100644 --- a/src/ParseCLP.ts +++ b/src/ParseCLP.ts @@ -11,6 +11,8 @@ export type PermissionsMap = { writeUserFields?: string[], readUserFields?: stri const PUBLIC_KEY = '*'; +// TODO: Typescript; This seems like a convenient way to define things quick & easily.. +// But it is quite type-unsafe right now. Seems to only be used in this file too. const VALID_PERMISSIONS: Map = new Map(); VALID_PERMISSIONS.set('get', {}); VALID_PERMISSIONS.set('find', {}); diff --git a/src/ParseFile.ts b/src/ParseFile.ts index 956bf9c65..a961ca3b4 100644 --- a/src/ParseFile.ts +++ b/src/ParseFile.ts @@ -4,8 +4,7 @@ /* global XMLHttpRequest, Blob */ import CoreManager from './CoreManager'; import type { FullOptions } from './RESTController'; - -const ParseError = require('./ParseError').default; +import ParseError from './ParseError' let XHR: typeof XMLHttpRequest = null; if (typeof XMLHttpRequest !== 'undefined') { @@ -126,7 +125,7 @@ class ParseFile { file: data, type: specifiedType, }; - } else if (data && typeof (data as Uri).uri === 'string' && (data as Uri).uri !== undefined) { + } else if (data && typeof (data as Uri).uri === 'string') { this._source = { format: 'uri', uri: (data as Uri).uri, diff --git a/src/ParseObject.ts b/src/ParseObject.ts index 44fae9c9e..1163d1937 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -2464,11 +2464,11 @@ const DefaultController = { // Queue up tasks for each object in the batch. // When every task is ready, the API request will execute - const batchReturned = new resolvingPromise(); + const batchReturned = resolvingPromise(); const batchReady = []; const batchTasks = []; batch.forEach((obj, index) => { - const ready = new resolvingPromise(); + const ready = resolvingPromise(); batchReady.push(ready); const task = function () { ready.resolve(); diff --git a/src/ParseRole.ts b/src/ParseRole.ts index 48c28f52b..badf6df69 100644 --- a/src/ParseRole.ts +++ b/src/ParseRole.ts @@ -42,7 +42,7 @@ class ParseRole extends ParseObject { * * @returns {string} the name of the role. */ - getName(): string | null | undefined { + getName(): string | null { const name = this.get('name'); if (name == null || typeof name === 'string') { return name; diff --git a/src/decode.ts b/src/decode.ts index 1c33b843e..43dc8d679 100644 --- a/src/decode.ts +++ b/src/decode.ts @@ -15,7 +15,7 @@ export default function decode(value: any): any { return value; } if (Array.isArray(value)) { - const dup: any = []; + const dup: any[] = []; value.forEach((v, i) => { dup[i] = decode(v); }); diff --git a/src/encode.ts b/src/encode.ts index 48350de06..b75775442 100644 --- a/src/encode.ts +++ b/src/encode.ts @@ -57,7 +57,7 @@ function encode( if (isNaN(value)) { throw new Error('Tried to encode an invalid date.'); } - return { __type: 'Date', iso: (value as any).toJSON() }; + return { __type: 'Date', iso: (value as Date).toJSON() }; } if ( Object.prototype.toString.call(value) === '[object RegExp]' && diff --git a/src/uuid.ts b/src/uuid.ts index 401427d20..8308a37e6 100644 --- a/src/uuid.ts +++ b/src/uuid.ts @@ -19,4 +19,5 @@ if (process.env.PARSE_BUILD === 'weapp') { uuid = v4; } +module.exports = uuid; export default uuid; From ee8adf3a224f37f233295662dc25a7e45009f8eb Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 06:07:59 +0700 Subject: [PATCH 14/27] added ts files to checks and fixed fixable strict compiler warnings --- src/CoreManager.ts | 69 ++++++++++++++------------- src/EventEmitter.ts | 4 +- src/LiveQueryClient.ts | 4 +- src/ObjectStateMutations.ts | 6 +-- src/Parse.ts | 4 +- src/ParseCLP.ts | 12 ++--- src/ParseConfig.ts | 2 +- src/ParseFile.ts | 34 ++++++------- src/ParseHooks.ts | 32 +++++++------ src/ParseObject.ts | 69 ++++++++++++++------------- src/ParseQuery.ts | 44 ++++++++--------- src/ParseRelation.ts | 8 +++- src/ParseSchema.ts | 4 +- src/ParseSession.ts | 4 +- src/ParseUser.ts | 8 ++-- src/Push.ts | 4 +- src/RESTController.ts | 7 +-- src/SingleInstanceStateController.ts | 2 +- src/Storage.ts | 2 +- src/StorageController.browser.ts | 1 + src/StorageController.default.ts | 1 + src/StorageController.react-native.ts | 1 + src/UniqueInstanceStateController.ts | 6 +-- src/decode.ts | 2 +- src/encode.ts | 2 +- src/unique.ts | 2 +- src/unsavedChildren.ts | 6 +-- tsconfig.json | 5 +- 28 files changed, 178 insertions(+), 167 deletions(-) diff --git a/src/CoreManager.ts b/src/CoreManager.ts index f4cd25f1c..3064fc4bd 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -1,6 +1,6 @@ import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMutations'; import type ParseFile from './ParseFile'; -import type { FileSource } from './ParseFile'; +import type { FileSaveOptions, FileSource } from './ParseFile'; import type { Op } from './ParseOp'; import type ParseObject from './ParseObject'; import type { QueryJSON } from './ParseQuery'; @@ -12,6 +12,7 @@ import type ParseSession from './ParseSession'; import type { HookDeclaration, HookDeleteArg } from './ParseHooks'; import type ParseConfig from './ParseConfig'; import type LiveQueryClient from './LiveQueryClient'; +import type ParseSchema from './ParseSchema'; type AnalyticsController = { track: (name: string, dimensions: { [key: string]: string }) => Promise, @@ -32,8 +33,8 @@ type CryptoController = { decrypt: (encryptedText: string, secretKey: any) => string, }; type FileController = { - saveFile: (name: string, source: FileSource, options: FullOptions) => Promise, - saveBase64: (name: string, source: FileSource, options: FullOptions) => Promise<{ name: string, url: string }>, + saveFile: (name: string, source: FileSource, options?: FullOptions) => Promise, + saveBase64: (name: string, source: FileSource, options?: FileSaveOptions) => Promise<{ name: string, url: string }>, download: (uri: string, options?: any) => Promise<{ base64?: string, contentType?: string }>, deleteFile: (name: string, options?: { useMasterKey?: boolean }) => Promise, }; @@ -46,19 +47,19 @@ type ObjectController = { forceFetch: boolean, options: RequestOptions ) => Promise, - save: (object: ParseObject | Array, options: RequestOptions) => Promise | ParseFile>, + save: (object: ParseObject | Array | null, options: RequestOptions) => Promise | ParseFile>, destroy: (object: ParseObject | Array, options: RequestOptions) => Promise>, }; type ObjectStateController = { - getState: (obj: any) => State | undefined, + getState: (obj: any) => State | null, initializeState: (obj: any, initial?: State) => State, - removeState: (obj: any) => State | undefined, + removeState: (obj: any) => State | null, getServerData: (obj: any) => AttributeMap, setServerData: (obj: any, attributes: AttributeMap) => void, getPendingOps: (obj: any) => Array, setPendingOp: (obj: any, attr: string, op?: Op) => void, pushPendingState: (obj: any) => void, - popPendingState: (obj: any) => OpsMap, + popPendingState: (obj: any) => OpsMap | undefined, mergeFirstPendingState: (obj: any) => void, getObjectCache: (obj: any) => ObjectCache, estimateAttribute: (obj: any, attr: string) => any, @@ -81,8 +82,8 @@ type RESTController = { handleError: (err?: any) => void, }; type SchemaController = { - purge: (className: string) => Promise, - get: (className: string, options?: RequestOptions) => Promise, + purge: (className: string) => Promise, + get: (className: string, options?: RequestOptions) => Promise<{ results: ParseSchema[] }>, delete: (className: string, options?: RequestOptions) => Promise, create: (className: string, params: any, options?: RequestOptions) => Promise, update: (className: string, params: any, options?: RequestOptions) => Promise, @@ -125,8 +126,8 @@ type LocalDatastoreController = { }; type UserController = { setCurrentUser: (user: ParseUser) => Promise, - currentUser: () => ParseUser | undefined, - currentUserAsync: () => Promise, + currentUser: () => ParseUser | null, + currentUserAsync: () => Promise, signUp: (user: ParseUser, attrs: AttributeMap, options: RequestOptions) => Promise, logIn: (user: ParseUser, options: RequestOptions) => Promise, loginAs: (user: ParseUser, userId: string) => Promise, @@ -143,12 +144,12 @@ type UserController = { requestEmailVerification: (email: string, options: RequestOptions) => Promise, }; type HooksController = { - get: (type: string, functionName?: string, triggerName?: string) => Promise, - create: (hook: HookDeclaration) => Promise, - remove: (hook: HookDeleteArg) => Promise, - update: (hook: HookDeclaration) => Promise, + get: (type: string, functionName?: string, triggerName?: string) => Promise, + create: (hook: HookDeclaration) => Promise, + remove: (hook: HookDeleteArg) => Promise, + update: (hook: HookDeclaration) => Promise, // Renamed to sendRequest since ParseHooks file & tests file uses this. (originally declared as just "send") - sendRequest?: (method: string, path: string, body?: any) => Promise, + sendRequest?: (method: string, path: string, body?: any) => Promise, }; type LiveQueryControllerType = { setDefaultLiveQueryClient(liveQueryClient: LiveQueryClient): void; @@ -313,7 +314,7 @@ const CoreManager = { }, getAnalyticsController(): AnalyticsController { - return config['AnalyticsController']; + return config['AnalyticsController']!; }, setCloudController(controller: CloudController) { @@ -322,7 +323,7 @@ const CoreManager = { }, getCloudController(): CloudController { - return config['CloudController']; + return config['CloudController']!; }, setConfigController(controller: ConfigController) { @@ -331,7 +332,7 @@ const CoreManager = { }, getConfigController(): ConfigController { - return config['ConfigController']; + return config['ConfigController']!; }, setCryptoController(controller: CryptoController) { @@ -357,7 +358,7 @@ const CoreManager = { }, getFileController(): FileController { - return config['FileController']; + return config['FileController']!; }, setInstallationController(controller: InstallationController) { @@ -366,7 +367,7 @@ const CoreManager = { }, getInstallationController(): InstallationController { - return config['InstallationController']; + return config['InstallationController']!; }, setLiveQuery(liveQuery: any) { @@ -383,7 +384,7 @@ const CoreManager = { }, getObjectController(): ObjectController { - return config['ObjectController']; + return config['ObjectController']!; }, setObjectStateController(controller: ObjectStateController) { @@ -414,7 +415,7 @@ const CoreManager = { }, getObjectStateController(): ObjectStateController { - return config['ObjectStateController']; + return config['ObjectStateController']!; }, setPushController(controller: PushController) { @@ -423,7 +424,7 @@ const CoreManager = { }, getPushController(): PushController { - return config['PushController']; + return config['PushController']!; }, setQueryController(controller: QueryController) { @@ -432,7 +433,7 @@ const CoreManager = { }, getQueryController(): QueryController { - return config['QueryController']; + return config['QueryController']!; }, setRESTController(controller: RESTController) { @@ -441,7 +442,7 @@ const CoreManager = { }, getRESTController(): RESTController { - return config['RESTController']; + return config['RESTController']!; }, setSchemaController(controller: SchemaController) { @@ -454,7 +455,7 @@ const CoreManager = { }, getSchemaController(): SchemaController { - return config['SchemaController']; + return config['SchemaController']!; }, setSessionController(controller: SessionController) { @@ -463,7 +464,7 @@ const CoreManager = { }, getSessionController(): SessionController { - return config['SessionController']; + return config['SessionController']!; }, setStorageController(controller: StorageController) { @@ -493,7 +494,7 @@ const CoreManager = { }, getLocalDatastoreController(): LocalDatastoreController { - return config['LocalDatastoreController']; + return config['LocalDatastoreController']!; }, setLocalDatastore(store: any) { @@ -505,7 +506,7 @@ const CoreManager = { }, getStorageController(): StorageController { - return config['StorageController']; + return config['StorageController']!; }, setAsyncStorage(storage: AsyncStorageType) { @@ -521,7 +522,7 @@ const CoreManager = { }, getWebSocketController(): new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController { - return config['WebSocketController']; + return config['WebSocketController']!; }, setUserController(controller: UserController) { @@ -548,7 +549,7 @@ const CoreManager = { }, getUserController(): UserController { - return config['UserController']; + return config['UserController']!; }, setLiveQueryController(controller: LiveQueryControllerType) { @@ -561,7 +562,7 @@ const CoreManager = { }, getLiveQueryController(): LiveQueryControllerType { - return config['LiveQueryController']; + return config['LiveQueryController']!; }, setHooksController(controller: HooksController) { @@ -570,7 +571,7 @@ const CoreManager = { }, getHooksController(): HooksController { - return config['HooksController']; + return config['HooksController']!; }, }; diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts index cb6897c0f..acf63b5f4 100644 --- a/src/EventEmitter.ts +++ b/src/EventEmitter.ts @@ -21,5 +21,5 @@ try { } catch (_) { // EventEmitter unavailable } -module.exports = EventEmitter; -export default EventEmitter; \ No newline at end of file +module.exports = EventEmitter!; +export default EventEmitter!; \ No newline at end of file diff --git a/src/LiveQueryClient.ts b/src/LiveQueryClient.ts index d942cb530..97667b435 100644 --- a/src/LiveQueryClient.ts +++ b/src/LiveQueryClient.ts @@ -190,9 +190,9 @@ class LiveQueryClient { * @param {string} sessionToken (optional) * @returns {LiveQuerySubscription | undefined} */ - subscribe(query: ParseQuery, sessionToken?: string): LiveQuerySubscription | undefined { + subscribe(query: ParseQuery, sessionToken?: string): LiveQuerySubscription { if (!query) { - return; + throw new ParseError(ParseError.INCORRECT_TYPE, 'Subscribe requires a query.') } const className = query.className; const queryJSON = query.toJSON(); diff --git a/src/ObjectStateMutations.ts b/src/ObjectStateMutations.ts index 04e8eeecb..219de91b8 100644 --- a/src/ObjectStateMutations.ts +++ b/src/ObjectStateMutations.ts @@ -56,7 +56,7 @@ export function pushPendingState(pendingOps: Array) { pendingOps.push({}); } -export function popPendingState(pendingOps: Array): OpsMap { +export function popPendingState(pendingOps: Array): OpsMap | undefined { const first = pendingOps.shift(); if (!pendingOps.length) { pendingOps[0] = {}; @@ -83,8 +83,8 @@ export function estimateAttribute( serverData: AttributeMap, pendingOps: Array, className: string, - id: string|undefined, - attr: string|undefined + id: string | undefined, + attr: string ): any { let value = serverData[attr]; for (let i = 0; i < pendingOps.length; i++) { diff --git a/src/Parse.ts b/src/Parse.ts index dbf3a0983..57269f6d4 100644 --- a/src/Parse.ts +++ b/src/Parse.ts @@ -78,7 +78,7 @@ interface ParseType { Session: typeof Session, Storage: typeof Storage, User: typeof User, - LiveQuery?: typeof LiveQuery, + LiveQuery?: LiveQuery, LiveQueryClient: typeof LiveQueryClient, initialize(applicationId: string, javaScriptKey: string): void, @@ -103,7 +103,7 @@ interface ParseType { _ajax(...args: any[]): void, _decode(...args: any[]): void, _encode(...args: any[]): void, - _getInstallationId?(): string, + _getInstallationId?(): Promise, enableLocalDatastore(polling: boolean, ms: number): void, isLocalDatastoreEnabled(): boolean, dumpLocalDatastore(): void, diff --git a/src/ParseCLP.ts b/src/ParseCLP.ts index 20e2984d7..6be55d917 100644 --- a/src/ParseCLP.ts +++ b/src/ParseCLP.ts @@ -7,7 +7,7 @@ import ParseUser from './ParseUser'; type Entity = ParseUser | ParseRole | string; type UsersMap = { [userId: string]: boolean | any }; -export type PermissionsMap = { writeUserFields?: string[], readUserFields?: string[], [permission: string]: UsersMap }; +export type PermissionsMap = { writeUserFields?: string[], readUserFields?: string[] } & { [permission: string]: UsersMap }; const PUBLIC_KEY = '*'; @@ -265,7 +265,7 @@ class ParseCLP { let name = role; if (role instanceof ParseRole) { // Normalize to the String name - name = role.getName(); + name = role.getName()!; } if (typeof name !== 'string') { throw new TypeError('role must be a Parse.Role or a String'); @@ -276,7 +276,7 @@ class ParseCLP { _parseEntity(entity: Entity) { let userId = entity; if (userId instanceof ParseUser) { - userId = userId.id; + userId = userId.id!; if (!userId) { throw new Error('Cannot get access for a Parse.User without an id.'); } @@ -358,7 +358,7 @@ class ParseCLP { } } - _getGroupPointerPermissions(operation: 'readUserFields' | 'writeUserFields'): string[] { + _getGroupPointerPermissions(operation: 'readUserFields' | 'writeUserFields'): string[] | undefined { return this.permissionsMap[operation]; } @@ -375,7 +375,7 @@ class ParseCLP { * @returns {string[]} User pointer fields */ getReadUserFields(): string[] { - return this._getGroupPointerPermissions('readUserFields'); + return this._getGroupPointerPermissions('readUserFields') || []; } /** @@ -391,7 +391,7 @@ class ParseCLP { * @returns {string[]} User pointer fields */ getWriteUserFields(): string[] { - return this._getGroupPointerPermissions('writeUserFields'); + return this._getGroupPointerPermissions('writeUserFields') || []; } /** diff --git a/src/ParseConfig.ts b/src/ParseConfig.ts index d39e97e70..89ed810b9 100644 --- a/src/ParseConfig.ts +++ b/src/ParseConfig.ts @@ -195,7 +195,7 @@ const DefaultController = { }); }, - save(attrs: { [key: string]: any }, masterKeyOnlyFlags: { [key: string]: any }) { + save(attrs?: { [key: string]: any }, masterKeyOnlyFlags?: { [key: string]: any }) { const RESTController = CoreManager.getRESTController(); const encodedAttrs = {}; for (const key in attrs) { diff --git a/src/ParseFile.ts b/src/ParseFile.ts index a961ca3b4..3904679d9 100644 --- a/src/ParseFile.ts +++ b/src/ParseFile.ts @@ -6,7 +6,7 @@ import CoreManager from './CoreManager'; import type { FullOptions } from './RESTController'; import ParseError from './ParseError' -let XHR: typeof XMLHttpRequest = null; +let XHR: typeof XMLHttpRequest = null as any; if (typeof XMLHttpRequest !== 'undefined') { XHR = XMLHttpRequest; } @@ -26,7 +26,7 @@ export type FileSource = | { format: 'base64', base64: string, - type: string, + type?: string, } | { format: 'uri', @@ -53,7 +53,7 @@ function b64Digit(number: number): string { throw new TypeError('Tried to encode large digit ' + number + ' in base64.'); } -type FileSaveOptions = FullOptions & { +export type FileSaveOptions = FullOptions & { metadata?: { [key: string]: any } tags?: { [key: string]: any } } @@ -71,8 +71,8 @@ class ParseFile { _previousSave?: Promise; _data?: string; _requestTask?: any; - _metadata?: Object; - _tags?: Object; + _metadata: Object; + _tags: Object; /** * @param name {String} The file's name. This will be prefixed by a unique @@ -170,7 +170,7 @@ class ParseFile { const controller = CoreManager.getFileController(); const result = await controller.download(this._url, options); this._data = result.base64; - return this._data; + return this._data!; } /** @@ -208,7 +208,7 @@ class ParseFile { * * @returns {object} */ - metadata(): Object { + metadata() { return this._metadata; } @@ -217,7 +217,7 @@ class ParseFile { * * @returns {object} */ - tags(): Object { + tags() { return this._tags; } @@ -256,7 +256,7 @@ class ParseFile { this._previousSave = controller.saveFile(this._name, this._source, options).then(res => { this._name = res.name; this._url = res.url; - this._data = null; + this._data = undefined; this._requestTask = null; return this; }); @@ -270,14 +270,14 @@ class ParseFile { const newSource = { format: 'base64' as const, base64: result.base64, - type: result.contentType, + type: result.contentType!, }; this._data = result.base64; this._requestTask = null; return controller.saveBase64(this._name, newSource, options); }) .then((res: { name?: string, url?: string }) => { - this._name = res.name; + this._name = res.name!; this._url = res.url; this._requestTask = null; return this; @@ -324,11 +324,11 @@ class ParseFile { } const destroyOptions = { useMasterKey: true }; if (options.hasOwnProperty('useMasterKey')) { - destroyOptions.useMasterKey = options.useMasterKey; + destroyOptions.useMasterKey = options.useMasterKey!; } const controller = CoreManager.getFileController(); return controller.deleteFile(this._name, destroyOptions).then(() => { - this._data = null; + this._data = undefined; this._requestTask = null; return this; }); @@ -415,7 +415,7 @@ class ParseFile { } static encodeBase64(bytes: Array | Uint8Array): string { - const chunks = []; + const chunks: string[] = []; chunks.length = Math.ceil(bytes.length / 3); for (let i = 0; i < chunks.length; i++) { const b1 = bytes[i * 3]; @@ -458,12 +458,12 @@ const DefaultController = { const newSource = { format: 'base64' as const, base64: data, - type: source.type || (source.file ? source.file.type : null), + type: source.type || (source.file ? source.file.type : undefined), }; return await DefaultController.saveBase64(name, newSource, options); }, - saveBase64: function (name: string, source: FileSource, options?: FileSaveOptions) { + saveBase64: function (name: string, source: FileSource, options: FileSaveOptions = {}) { if (source.format !== 'base64') { throw new Error('saveBase64 can only be used with Base64-type sources.'); } @@ -542,7 +542,7 @@ const DefaultController = { const headers = { 'X-Parse-Application-ID': CoreManager.get('APPLICATION_ID'), }; - if (options.useMasterKey) { + if (options?.useMasterKey) { headers['X-Parse-Master-Key'] = CoreManager.get('MASTER_KEY'); } let url = CoreManager.get('SERVER_URL'); diff --git a/src/ParseHooks.ts b/src/ParseHooks.ts index 8a8571a1f..c6edf219c 100644 --- a/src/ParseHooks.ts +++ b/src/ParseHooks.ts @@ -22,15 +22,15 @@ export function createFunction(functionName: string, url: string) { return create({ functionName: functionName, url: url }); } -export function createTrigger(className, triggerName, url) { +export function createTrigger(className: string, triggerName: string, url: string) { return create({ className: className, triggerName: triggerName, url: url }); } -export function create(hook) { +export function create(hook: HookDeclaration) { return CoreManager.getHooksController().create(hook); } -export function updateFunction(functionName, url) { +export function updateFunction(functionName: string, url: string) { return update({ functionName: functionName, url: url }); } @@ -38,19 +38,19 @@ export function updateTrigger(className: string, triggerName: string, url: strin return update({ className: className, triggerName: triggerName, url: url }); } -export function update(hook) { +export function update(hook: HookDeclaration) { return CoreManager.getHooksController().update(hook); } -export function removeFunction(functionName) { +export function removeFunction(functionName: string) { return remove({ functionName: functionName }); } -export function removeTrigger(className, triggerName) { +export function removeTrigger(className: string, triggerName: string) { return remove({ className: className, triggerName: triggerName }); } -export function remove(hook) { +export function remove(hook: HookDeleteArg) { return CoreManager.getHooksController().remove(hook); } @@ -82,13 +82,14 @@ const DefaultController = { remove(hook: { functionName: string } | { className: string, triggerName: string }) { let url: string; + const putParams = { ...hook }; if ('functionName' in hook) { url = '/hooks/functions/' + hook.functionName; - delete hook.functionName; + delete (putParams as Partial).functionName; } else if (hook.className && hook.triggerName) { url = '/hooks/triggers/' + hook.className + '/' + hook.triggerName; - delete hook.className; - delete hook.triggerName; + delete (putParams as Partial).className; + delete (putParams as Partial).triggerName; } else { return Promise.reject({ error: 'invalid hook declaration', code: 143 }); } @@ -97,17 +98,18 @@ const DefaultController = { update(hook: HookDeclaration) { let url: string; + const postParams = { ...hook }; if ('functionName' in hook && hook.url) { url = '/hooks/functions/' + hook.functionName; - delete hook.functionName; + delete (postParams as Partial).functionName; } else if ('className' in hook && hook.triggerName && hook.url) { url = '/hooks/triggers/' + hook.className + '/' + hook.triggerName; - delete hook.className; - delete hook.triggerName; + delete (postParams as Partial).className; + delete (postParams as Partial).triggerName; } else { return Promise.reject({ error: 'invalid hook declaration', code: 143 }); } - return this.sendRequest('PUT', url, hook); + return this.sendRequest('PUT', url, postParams); }, sendRequest(method: string, url: string, body?: any) { @@ -116,7 +118,7 @@ const DefaultController = { .then(res => { const decoded = decode(res); if (decoded) { - return Promise.resolve(decoded); + return Promise.resolve(decoded); } return Promise.reject( new ParseError(ParseError.INVALID_JSON, 'The server returned an invalid response.') diff --git a/src/ParseObject.ts b/src/ParseObject.ts index 1163d1937..2a7f5a3d2 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -370,10 +370,10 @@ class ParseObject { } } if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = parseDate(decoded.createdAt); + decoded.createdAt = parseDate(decoded.createdAt) || undefined; } if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = parseDate(decoded.updatedAt); + decoded.updatedAt = parseDate(decoded.updatedAt) || undefined; } if (!decoded.updatedAt && decoded.createdAt) { decoded.updatedAt = decoded.createdAt; @@ -415,12 +415,14 @@ class ParseObject { let attr; const stateController = CoreManager.getObjectStateController(); const pending = stateController.popPendingState(this._getStateIdentifier()); - for (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); + if (pending) { + for (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) { @@ -708,7 +710,7 @@ class ParseObject { set(keyOrAttributes: string | AttributeMap, valueOrOptions?: any, options?: any): ParseObject | boolean { let changes: AttributeMap = {}; const newOps = {}; - let key: string; + let key: string | undefined; if (keyOrAttributes && typeof keyOrAttributes === 'object') { changes = keyOrAttributes; options = valueOrOptions; @@ -720,7 +722,8 @@ class ParseObject { } options = options || {}; - let readonly = []; + /** Readonly attributes of the object class */ + let readonly: string[] = []; if (typeof ((this.constructor as any).readOnlyAttributes) === 'function') { readonly = readonly.concat((this.constructor as any).readOnlyAttributes()); } @@ -1172,13 +1175,13 @@ class ParseObject { if (Array.isArray(options.include)) { options.include.forEach(key => { if (Array.isArray(key)) { - fetchOptions.include = fetchOptions.include.concat(key); + fetchOptions.include = fetchOptions.include!.concat(key); } else { (fetchOptions.include as string[]).push(key); } }); } else { - fetchOptions.include.push(options.include); + fetchOptions.include.push(options.include!); // already checked hasOwnProperty('include') } } const controller = CoreManager.getObjectController(); @@ -1309,14 +1312,14 @@ class ParseObject { * completes. */ save( - arg1: undefined | string | { [attr: string]: any }, + arg1: undefined | string | { [attr: string]: any } | null, arg2: SaveOptions | any, arg3?: SaveOptions ): Promise { - let attrs: { [attr: string]: any }; - let options: SaveOptions; - if (typeof arg1 === 'object' || typeof arg1 === 'undefined') { - attrs = arg1; + let attrs: { [attr: string]: any } | null; + let options: SaveOptions | undefined; + if (typeof arg1 === 'object' || typeof arg1 === 'undefined' || arg1 == null) { + attrs = (arg1 as { [attr: string]: any }) || null; if (typeof arg2 === 'object') { options = arg2; } @@ -1694,8 +1697,8 @@ class ParseObject { return CoreManager.getObjectController().fetch(list, false, queryOptions); } - static handleIncludeOptions(options) { - let include = []; + static handleIncludeOptions(options: { include?: string | string[] }) { + let include: string[] = []; if (Array.isArray(options.include)) { options.include.forEach(key => { if (Array.isArray(key)) { @@ -1705,7 +1708,7 @@ class ParseObject { } }); } else { - include.push(options.include); + include.push(options.include!); } return include; } @@ -2224,7 +2227,7 @@ const DefaultController = { const ids: string[] = []; let className: null | string = null; const results: ParseObject[] = []; - let error = null; + let error: ParseError | null = null; target.forEach(el => { if (error) { return; @@ -2242,7 +2245,7 @@ const DefaultController = { error = new ParseError(ParseError.MISSING_OBJECT_ID, 'All objects must have an ID'); } if (forceFetch || !el.isDataAvailable()) { - ids.push(el.id); + ids.push(el.id!); // Already checked e.id above. objs.push(el); } results.push(el); @@ -2251,7 +2254,7 @@ const DefaultController = { return Promise.reject(error); } // Construct a ParseQuery that finds objects with matching IDs - const query = new ParseQuery(className); + const query = new ParseQuery(className!); query.containedIn('objectId', ids); if (options && options.include) { query.include(options.include); @@ -2260,7 +2263,7 @@ const DefaultController = { return query.find(options).then(async (objects: ParseObject[]) => { const idMap: Record = {}; objects.forEach(o => { - idMap[o.id] = o; + idMap[o.id!] = o; }); for (let i = 0; i < objs.length; i++) { const obj = objs[i]; @@ -2344,7 +2347,7 @@ const DefaultController = { batches.pop(); } let deleteCompleted = Promise.resolve(); - const errors = []; + const errors: ParseError[] = []; batches.forEach(batch => { deleteCompleted = deleteCompleted.then(() => { return RESTController.request( @@ -2396,7 +2399,7 @@ const DefaultController = { return Promise.resolve(target); }, - save(target: ParseObject | Array, options: RequestOptions) { + save(target: ParseObject | Array | null, options: RequestOptions) { const batchSize = options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE'); const localDatastore = CoreManager.getLocalDatastore(); @@ -2422,7 +2425,7 @@ const DefaultController = { } unsaved = unique(unsaved); - const filesSaved: Array> = []; + const filesSaved: Array | undefined> = []; let pending: Array = []; unsaved.forEach(el => { if (el instanceof ParseFile) { @@ -2433,14 +2436,14 @@ const DefaultController = { }); return Promise.all(filesSaved).then(() => { - let objectError = null; + let objectError: null | ParseError = null; return continueWhile( () => { return pending.length > 0; }, () => { - const batch = []; - const nextPending = []; + const batch: ParseObject[] = []; + const nextPending: ParseObject[] = []; pending.forEach(el => { if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(el, 'id') && !el.id) { throw new ParseError( @@ -2465,8 +2468,8 @@ const DefaultController = { // Queue up tasks for each object in the batch. // When every task is ready, the API request will execute const batchReturned = resolvingPromise(); - const batchReady = []; - const batchTasks = []; + const batchReady: ReturnType>[] = []; + const batchTasks: Promise[] = []; batch.forEach((obj, index) => { const ready = resolvingPromise(); batchReady.push(ready); @@ -2525,7 +2528,7 @@ const DefaultController = { for (const object of target) { // Make sure that it is a ParseObject before updating it into the localDataStore if (object instanceof ParseObject) { - await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); + await localDatastore._updateLocalIdForObject(mapIdForPin[object.id!], object); await localDatastore._updateObjectIfPinned(object); } } diff --git a/src/ParseQuery.ts b/src/ParseQuery.ts index f9a692dce..6639bfb66 100644 --- a/src/ParseQuery.ts +++ b/src/ParseQuery.ts @@ -97,7 +97,7 @@ function quote(s: string): string { * @returns {string} */ function _getClassNameFromQueries(queries: Array): string | null { - let className = null; + let className: string | null = null; queries.forEach(q => { if (!className) { className = q.className; @@ -270,9 +270,9 @@ class ParseQuery { _skip: number; _count: boolean; _order: Array; - _readPreference: string; - _includeReadPreference: string; - _subqueryReadPreference: string; + _readPreference: string | null; + _includeReadPreference: string | null; + _subqueryReadPreference: string | null; _queriesLocalDatastore: boolean; _localDatastorePinName: any; _extraOptions: { [key: string]: any }; @@ -715,7 +715,7 @@ class ParseQuery { if (this._explain) { return response.results; } - const results = response.results.map(data => { + const results = response.results!.map(data => { // In cases of relations, the server may send back a className // on the top level of the payload const override = response.className || this.className; @@ -729,7 +729,7 @@ class ParseQuery { if (select) { handleSelectResult(data, select); } - if (options.json) { + if (options?.json) { return data; } else { return ParseObject.fromJSON(data, !select); @@ -800,7 +800,7 @@ class ParseQuery { params.count = 1; return controller.find(this.className, params, findOptions).then(result => { - return result.count; + return result.count!; }); } @@ -831,7 +831,7 @@ class ParseQuery { hint: this._hint, }; return controller.aggregate(this.className, params, distinctOptions).then(results => { - return results.results; + return results.results!; }); } @@ -874,7 +874,7 @@ class ParseQuery { readPreference: this._readPreference, }; return controller.aggregate(this.className, params, aggregateOptions).then(results => { - return results.results; + return results.results!; }); } @@ -894,9 +894,7 @@ class ParseQuery { * @returns {Promise} A promise that is resolved with the object when * the query completes. */ - first(options?: QueryOptions): Promise { - options = options || {}; - + first(options: QueryOptions = {}): Promise { const findOptions: QueryOptions = {}; if (options.hasOwnProperty('useMasterKey')) { findOptions.useMasterKey = options.useMasterKey; @@ -926,7 +924,7 @@ class ParseQuery { } return controller.find(this.className, params, findOptions).then(response => { - const objects = response.results; + const objects = response.results!; if (!objects[0]) { return undefined; } @@ -1023,7 +1021,7 @@ class ParseQuery { } let finished = false; - let previousResults = []; + let previousResults: ParseObject[] = []; return continueWhile( () => { return !finished; @@ -1132,7 +1130,7 @@ class ParseQuery { callback: (currentObject: ParseObject, index: number, query: ParseQuery) => any, options?: BatchOptions ): Promise> { - const array = []; + const array: any[] = []; let index = 0; await this.each(object => { return Promise.resolve(callback(object, index, this)).then(result => { @@ -1220,7 +1218,7 @@ class ParseQuery { callback: (currentObject: ParseObject, index: number, query: ParseQuery) => boolean, options?: BatchOptions ): Promise> { - const array = []; + const array: ParseObject[] = []; let index = 0; await this.each(object => { return Promise.resolve(callback(object, index, this)).then(flag => { @@ -1996,8 +1994,8 @@ class ParseQuery { subqueryReadPreference?: string ): ParseQuery { this._readPreference = readPreference; - this._includeReadPreference = includeReadPreference; - this._subqueryReadPreference = subqueryReadPreference; + this._includeReadPreference = includeReadPreference || null; + this._subqueryReadPreference = subqueryReadPreference || null; return this; } @@ -2011,7 +2009,7 @@ class ParseQuery { async subscribe(sessionToken?: string): Promise { const currentUser = await CoreManager.getUserController().currentUserAsync(); if (!sessionToken) { - sessionToken = currentUser ? currentUser.getSessionToken() : undefined; + sessionToken = currentUser ? currentUser.getSessionToken() || undefined : undefined; } const liveQueryClient = await CoreManager.getLiveQueryController().getDefaultLiveQueryClient(); if (liveQueryClient.shouldOpen()) { @@ -2037,7 +2035,7 @@ class ParseQuery { */ static or(...queries: Array): ParseQuery { const className = _getClassNameFromQueries(queries); - const query = new ParseQuery(className); + const query = new ParseQuery(className!); // Cast to !; Checked inside ParseQuery constructor anyway query._orQuery(queries); return query; } @@ -2056,7 +2054,7 @@ class ParseQuery { */ static and(...queries: Array): ParseQuery { const className = _getClassNameFromQueries(queries); - const query = new ParseQuery(className); + const query = new ParseQuery(className!); // Cast to !; Checked inside ParseQuery constructor anyway query._andQuery(queries); return query; } @@ -2075,7 +2073,7 @@ class ParseQuery { */ static nor(...queries: Array): ParseQuery { const className = _getClassNameFromQueries(queries); - const query = new ParseQuery(className); + const query = new ParseQuery(className!); // Cast to !; Checked inside ParseQuery constructor anyway query._norQuery(queries); return query; } @@ -2115,7 +2113,7 @@ class ParseQuery { * @param {string} name The name of query source. * @returns {Parse.Query} Returns the query, so you can chain this call. */ - fromPinWithName(name?: string): ParseQuery { + fromPinWithName(name?: string | null): ParseQuery { const localDatastore = CoreManager.getLocalDatastore(); if (localDatastore.checkIfEnabled()) { this._queriesLocalDatastore = true; diff --git a/src/ParseRelation.ts b/src/ParseRelation.ts index 1633d3f96..23b9f5c19 100644 --- a/src/ParseRelation.ts +++ b/src/ParseRelation.ts @@ -77,7 +77,9 @@ class ParseRelation { if (objects.length === 0) { return parent; } - parent.set(this.key, change); + if (this.key) { + parent.set(this.key, change); + } this.targetClassName = change._targetClassName; return parent; } @@ -99,7 +101,9 @@ class ParseRelation { if (objects.length === 0) { return; } - this.parent.set(this.key, change); + if (this.key) { + this.parent.set(this.key, change); + } this.targetClassName = change._targetClassName; } diff --git a/src/ParseSchema.ts b/src/ParseSchema.ts index 8a1e16a8b..de5bca077 100644 --- a/src/ParseSchema.ts +++ b/src/ParseSchema.ts @@ -473,14 +473,14 @@ class ParseSchema { } const DefaultController = { - send(className: string, method: string, params: any = {}): Promise { + send(className: string, method: string, params: any = {}): Promise { const RESTController = CoreManager.getRESTController(); return RESTController.request(method, `schemas/${className}`, params, { useMasterKey: true, }); }, - get(className: string): Promise { + get(className: string): Promise<{ results: ParseSchema[] }> { return this.send(className, 'GET'); }, diff --git a/src/ParseSession.ts b/src/ParseSession.ts index cfb678373..ab64e43a3 100644 --- a/src/ParseSession.ts +++ b/src/ParseSession.ts @@ -57,7 +57,7 @@ class ParseSession extends ParseObject { options = options || {}; const controller = CoreManager.getSessionController(); - const sessionOptions : FullOptions = {}; + const sessionOptions: FullOptions = {}; if (options.hasOwnProperty('useMasterKey')) { sessionOptions.useMasterKey = options.useMasterKey; } @@ -65,7 +65,7 @@ class ParseSession extends ParseObject { if (!user) { return Promise.reject('There is no current user.'); } - sessionOptions.sessionToken = user.getSessionToken(); + sessionOptions.sessionToken = user.getSessionToken() || undefined; return controller.getSession(sessionOptions); }); } diff --git a/src/ParseUser.ts b/src/ParseUser.ts index a38f04cfd..684873a5d 100644 --- a/src/ParseUser.ts +++ b/src/ParseUser.ts @@ -30,7 +30,7 @@ type AuthProviderType = { const CURRENT_USER_KEY = 'currentUser'; let canUseCurrentUser = !CoreManager.get('IS_NODE'); let currentUserCacheMatchesDisk = false; -let currentUserCache = null; +let currentUserCache: ParseUser | null = null; const authProviders: { [key: string]: AuthProviderType } = {}; @@ -93,7 +93,7 @@ class ParseUser extends ParseObject { */ linkWith( provider: AuthProviderType, - options: { authData?: AuthData }, + options: { authData?: AuthData | null }, saveOpts: FullOptions = {} ): Promise { saveOpts.sessionToken = saveOpts.sessionToken || this.getSessionToken() || ''; @@ -134,7 +134,7 @@ class ParseUser extends ParseObject { }); } else { return new Promise((resolve, reject) => { - provider.authenticate({ + provider.authenticate!({ success: (provider, result) => { const opts: { authData?: AuthData } = {}; opts.authData = result; @@ -479,7 +479,7 @@ class ParseUser extends ParseObject { loginOptions.installationId = options.installationId; } if (options.hasOwnProperty('usePost')) { - loginOptions.usePost = options.usePost; + loginOptions.usePost = options.usePost!; } if ( options.hasOwnProperty('context') && diff --git a/src/Push.ts b/src/Push.ts index a38c35dcd..d6b91b977 100644 --- a/src/Push.ts +++ b/src/Push.ts @@ -71,7 +71,7 @@ export function send(data: PushData, options: FullOptions = {}): Promise const pushOptions = { useMasterKey: true }; if (options.hasOwnProperty('useMasterKey')) { - pushOptions.useMasterKey = options.useMasterKey; + pushOptions.useMasterKey = options.useMasterKey!; } return CoreManager.getPushController().send(data, pushOptions); @@ -93,7 +93,7 @@ export function send(data: PushData, options: FullOptions = {}): Promise export function getPushStatus(pushStatusId: string, options: FullOptions = {}): Promise { const pushOptions = { useMasterKey: true }; if (options.hasOwnProperty('useMasterKey')) { - pushOptions.useMasterKey = options.useMasterKey; + pushOptions.useMasterKey = options.useMasterKey!; } const query = new ParseQuery('_PushStatus'); return query.get(pushStatusId, pushOptions); diff --git a/src/RESTController.ts b/src/RESTController.ts index b4758f4b5..a4bd56d2e 100644 --- a/src/RESTController.ts +++ b/src/RESTController.ts @@ -31,7 +31,7 @@ export type FullOptions = { requestTask?: any, }; -let XHR: typeof XMLHttpRequest = null; +let XHR: typeof XMLHttpRequest = null as any; if (typeof XMLHttpRequest !== 'undefined') { XHR = XMLHttpRequest; } @@ -117,8 +117,8 @@ const RESTController = { response = JSON.parse(xhr.responseText); headers = {}; if (typeof xhr.getResponseHeader === 'function' && xhr.getResponseHeader('access-control-expose-headers')) { - const responseHeaders = xhr.getResponseHeader('access-control-expose-headers').split(', '); - responseHeaders.forEach(header => { + const responseHeaders = xhr.getResponseHeader('access-control-expose-headers')?.split(', '); + responseHeaders?.forEach(header => { headers[header] = xhr.getResponseHeader(header.toLowerCase()); }); } @@ -348,3 +348,4 @@ const RESTController = { }; module.exports = RESTController; +export default RESTController; \ No newline at end of file diff --git a/src/SingleInstanceStateController.ts b/src/SingleInstanceStateController.ts index d3296c25a..3be62c78d 100644 --- a/src/SingleInstanceStateController.ts +++ b/src/SingleInstanceStateController.ts @@ -81,7 +81,7 @@ export function pushPendingState(obj: ObjectIdentifier) { ObjectStateMutations.pushPendingState(pendingOps); } -export function popPendingState(obj: ObjectIdentifier): OpsMap { +export function popPendingState(obj: ObjectIdentifier): OpsMap | undefined { const pendingOps = initializeState(obj).pendingOps; return ObjectStateMutations.popPendingState(pendingOps); } diff --git a/src/Storage.ts b/src/Storage.ts index bcc47a990..0af496743 100644 --- a/src/Storage.ts +++ b/src/Storage.ts @@ -34,7 +34,7 @@ const Storage = { return controller.setItem(path, value); }, - setItemAsync(path: string, value: string | null): Promise { + setItemAsync(path: string, value: string): Promise { const controller = CoreManager.getStorageController(); if (controller.async === 1) { return controller.setItemAsync(path, value); diff --git a/src/StorageController.browser.ts b/src/StorageController.browser.ts index 86d3f7404..9a65ec298 100644 --- a/src/StorageController.browser.ts +++ b/src/StorageController.browser.ts @@ -38,3 +38,4 @@ const StorageController = { }; module.exports = StorageController; +export default StorageController; \ No newline at end of file diff --git a/src/StorageController.default.ts b/src/StorageController.default.ts index 8e0bdd7fb..eda3f0d45 100644 --- a/src/StorageController.default.ts +++ b/src/StorageController.default.ts @@ -37,3 +37,4 @@ const StorageController = { }; module.exports = StorageController; +export default StorageController; \ No newline at end of file diff --git a/src/StorageController.react-native.ts b/src/StorageController.react-native.ts index c80844ebb..77a3ae069 100644 --- a/src/StorageController.react-native.ts +++ b/src/StorageController.react-native.ts @@ -85,3 +85,4 @@ const StorageController = { }; module.exports = StorageController; +export default StorageController; \ No newline at end of file diff --git a/src/UniqueInstanceStateController.ts b/src/UniqueInstanceStateController.ts index 50260209b..56763e3ae 100644 --- a/src/UniqueInstanceStateController.ts +++ b/src/UniqueInstanceStateController.ts @@ -11,7 +11,7 @@ import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMuta let objectState = new WeakMap(); -export function getState(obj: ParseObject): State | null | undefined { +export function getState(obj: ParseObject): State | null { const classData = objectState.get(obj); return classData || null; } @@ -35,7 +35,7 @@ export function initializeState(obj: ParseObject, initial?: State): State { return state; } -export function removeState(obj: ParseObject): State | null | undefined { +export function removeState(obj: ParseObject): State | null { const state = getState(obj); if (state === null) { return null; @@ -75,7 +75,7 @@ export function pushPendingState(obj: ParseObject) { ObjectStateMutations.pushPendingState(pendingOps); } -export function popPendingState(obj: ParseObject): OpsMap { +export function popPendingState(obj: ParseObject): OpsMap | undefined { const pendingOps = initializeState(obj).pendingOps; return ObjectStateMutations.popPendingState(pendingOps); } diff --git a/src/decode.ts b/src/decode.ts index 43dc8d679..4e4a6cfbe 100644 --- a/src/decode.ts +++ b/src/decode.ts @@ -32,7 +32,7 @@ export default function decode(value: any): any { } if (value.__type === 'Relation') { // The parent and key fields will be populated by the parent - const relation = new ParseRelation(null, null); + const relation = new ParseRelation(undefined, undefined); relation.targetClassName = value.className; return relation; } diff --git a/src/encode.ts b/src/encode.ts index b75775442..86148e8a4 100644 --- a/src/encode.ts +++ b/src/encode.ts @@ -16,7 +16,7 @@ function encode( disallowObjects: boolean, forcePointers: boolean, seen: Array, - offline: boolean + offline?: boolean ): any { if (value instanceof ParseObject) { if (disallowObjects) { diff --git a/src/unique.ts b/src/unique.ts index 169c288f5..1ee8f2cb1 100644 --- a/src/unique.ts +++ b/src/unique.ts @@ -6,7 +6,7 @@ import arrayContainsObject from './arrayContainsObject'; import ParseObject from './ParseObject'; export default function unique(arr: Array): Array { - const uniques = []; + const uniques: T[] = []; arr.forEach(value => { if (value instanceof ParseObject) { if (!arrayContainsObject(uniques, value)) { diff --git a/src/unsavedChildren.ts b/src/unsavedChildren.ts index 1411f0d1c..9a55c722e 100644 --- a/src/unsavedChildren.ts +++ b/src/unsavedChildren.ts @@ -24,7 +24,7 @@ export default function unsavedChildren( allowDeepUnsaved?: boolean ): Array { const encountered = { - objects: {}, + objects: {} as Record, files: [], }; const identifier = obj.className + ':' + obj._getId(); @@ -35,10 +35,10 @@ export default function unsavedChildren( traverse(attributes[attr], encountered, false, !!allowDeepUnsaved); } } - const unsaved = []; + const unsaved: ParseObject[] = []; for (const id in encountered.objects) { if (id !== identifier && encountered.objects[id] !== true) { - unsaved.push(encountered.objects[id]); + unsaved.push(encountered.objects[id] as ParseObject); } } return unsaved.concat(encountered.files); diff --git a/tsconfig.json b/tsconfig.json index 051477c29..b5166cc62 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,8 +8,7 @@ "noImplicitAny": false, "allowJs": false }, - "files": [ - "src/Parse.ts", - "src/ParseSession.ts" + "include": [ + "src/*.ts" ] } From a0d2683327474e10e6347f85241829378e37b13c Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 06:50:35 +0700 Subject: [PATCH 15/27] more, localdatastore --- src/CoreManager.ts | 30 +------- ...ryptoController.js => CryptoController.ts} | 5 +- ...oller.js => IndexedDBStorageController.ts} | 5 +- src/InstallationController.ts | 1 + src/{LocalDatastore.js => LocalDatastore.ts} | 10 +-- ... LocalDatastoreController.react-native.ts} | 1 + ...troller.js => LocalDatastoreController.ts} | 9 ++- src/Parse.ts | 75 ++++++++++--------- src/ParseQuery.ts | 2 +- src/Storage.ts | 26 +++++++ 10 files changed, 89 insertions(+), 75 deletions(-) rename src/{CryptoController.js => CryptoController.ts} (78%) rename src/{IndexedDBStorageController.js => IndexedDBStorageController.ts} (82%) rename src/{LocalDatastore.js => LocalDatastore.ts} (98%) rename src/{LocalDatastoreController.react-native.js => LocalDatastoreController.react-native.ts} (98%) rename src/{LocalDatastoreController.js => LocalDatastoreController.ts} (87%) diff --git a/src/CoreManager.ts b/src/CoreManager.ts index 3064fc4bd..661da25e8 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -13,6 +13,7 @@ import type { HookDeclaration, HookDeleteArg } from './ParseHooks'; import type ParseConfig from './ParseConfig'; import type LiveQueryClient from './LiveQueryClient'; import type ParseSchema from './ParseSchema'; +import type { StorageController } from './Storage'; type AnalyticsController = { track: (name: string, dimensions: { [key: string]: string }) => Promise, @@ -78,7 +79,7 @@ type QueryController = { }; type RESTController = { request: (method: string, path: string, data?: any, options?: RequestOptions) => Promise, - ajax: (method: string, url: string, data: any, headers?: any, options?: FullOptions) => Promise, + ajax: (method: string, url: string, data: any, headers?: any, options?: FullOptions) => Promise, handleError: (err?: any) => void, }; type SchemaController = { @@ -92,37 +93,14 @@ type SchemaController = { type SessionController = { getSession: (token: RequestOptions) => Promise, }; -type StorageController = - | { - async: 0, - getItem: (path: string) => string | null, - setItem: (path: string, value: string) => void, - removeItem: (path: string) => void, - getItemAsync?: (path: string) => Promise, - setItemAsync?: (path: string, value: string) => Promise, - removeItemAsync?: (path: string) => Promise, - clear: () => void, - getAllKeys?: () => Array - getAllKeysAsync?: () => Promise> - } - | { - async: 1, - getItem?: (path: string) => string | null, - setItem?: (path: string, value: string) => void, - removeItem?: (path: string) => void, - getItemAsync: (path: string) => Promise, - setItemAsync: (path: string, value: string) => Promise, - removeItemAsync: (path: string) => Promise, - clear: () => void, - getAllKeys?: () => Array - getAllKeysAsync?: () => Promise> - }; type LocalDatastoreController = { fromPinWithName: (name: string) => any | undefined, pinWithName: (name: string, objects: any) => void, unPinWithName: (name: string) => void, getAllContents: () => any | undefined, clear: () => void, + // Use for testing + // getRawStorage(): Promise, }; type UserController = { setCurrentUser: (user: ParseUser) => Promise, diff --git a/src/CryptoController.js b/src/CryptoController.ts similarity index 78% rename from src/CryptoController.js rename to src/CryptoController.ts index 49b7fc725..fd27a4bd2 100644 --- a/src/CryptoController.js +++ b/src/CryptoController.ts @@ -11,15 +11,16 @@ if (process.env.PARSE_BUILD === 'react-native') { } const CryptoController = { - encrypt(obj: any, secretKey: string): ?string { + encrypt(obj: any, secretKey: string): string { const encrypted = AES.encrypt(JSON.stringify(obj), secretKey); return encrypted.toString(); }, - decrypt(encryptedText: string, secretKey: string): ?string { + decrypt(encryptedText: string, secretKey: string): string { const decryptedStr = AES.decrypt(encryptedText, secretKey).toString(ENC); return decryptedStr; }, }; module.exports = CryptoController; +export default CryptoController; diff --git a/src/IndexedDBStorageController.js b/src/IndexedDBStorageController.ts similarity index 82% rename from src/IndexedDBStorageController.js rename to src/IndexedDBStorageController.ts index da2d2e973..3dc0e8fc6 100644 --- a/src/IndexedDBStorageController.js +++ b/src/IndexedDBStorageController.ts @@ -4,12 +4,14 @@ /* global window */ import { createStore, del, set, get, clear, keys } from 'idb-keyval'; +import type { StorageController } from './Storage'; +let IndexedDBStorageController: StorageController; if (typeof window !== 'undefined' && window.indexedDB) { try { const ParseStore = createStore('parseDB', 'parseStore'); - const IndexedDBStorageController = { + IndexedDBStorageController = { async: 1, getItemAsync(path: string) { return get(path, ParseStore); @@ -37,3 +39,4 @@ if (typeof window !== 'undefined' && window.indexedDB) { // IndexedDB not supported module.exports = undefined; } +export default IndexedDBStorageController; \ No newline at end of file diff --git a/src/InstallationController.ts b/src/InstallationController.ts index 410b9b1b5..1322a65f3 100644 --- a/src/InstallationController.ts +++ b/src/InstallationController.ts @@ -36,3 +36,4 @@ const InstallationController = { }; module.exports = InstallationController; +export default InstallationController; \ No newline at end of file diff --git a/src/LocalDatastore.js b/src/LocalDatastore.ts similarity index 98% rename from src/LocalDatastore.js rename to src/LocalDatastore.ts index bf552d09d..213b9d0c0 100644 --- a/src/LocalDatastore.js +++ b/src/LocalDatastore.ts @@ -37,12 +37,12 @@ const LocalDatastore = { return controller.fromPinWithName(name); }, - pinWithName(name: string, value: any): Promise { + async pinWithName(name: string, value: any): Promise { const controller = CoreManager.getLocalDatastoreController(); return controller.pinWithName(name, value); }, - unPinWithName(name: string): Promise { + async unPinWithName(name: string): Promise { const controller = CoreManager.getLocalDatastoreController(); return controller.unPinWithName(name); }, @@ -55,10 +55,10 @@ const LocalDatastore = { // Use for testing _getRawStorage(): Promise { const controller = CoreManager.getLocalDatastoreController(); - return controller.getRawStorage(); + return (controller as any).getRawStorage(); }, - _clear(): Promise { + async _clear(): Promise { const controller = CoreManager.getLocalDatastoreController(); return controller.clear(); }, @@ -376,7 +376,7 @@ const LocalDatastore = { return `${OBJECT_PREFIX}${object.className}_${objectId}`; }, - getPinName(pinName: ?string) { + getPinName(pinName?: string) { if (!pinName || pinName === DEFAULT_PIN) { return DEFAULT_PIN; } diff --git a/src/LocalDatastoreController.react-native.js b/src/LocalDatastoreController.react-native.ts similarity index 98% rename from src/LocalDatastoreController.react-native.js rename to src/LocalDatastoreController.react-native.ts index 74ebde95f..7add98fbd 100644 --- a/src/LocalDatastoreController.react-native.js +++ b/src/LocalDatastoreController.react-native.ts @@ -86,3 +86,4 @@ const LocalDatastoreController = { }; module.exports = LocalDatastoreController; +export default LocalDatastoreController; \ No newline at end of file diff --git a/src/LocalDatastoreController.js b/src/LocalDatastoreController.ts similarity index 87% rename from src/LocalDatastoreController.js rename to src/LocalDatastoreController.ts index 7116f28fd..066e15826 100644 --- a/src/LocalDatastoreController.js +++ b/src/LocalDatastoreController.ts @@ -5,7 +5,7 @@ import { isLocalDatastoreKey } from './LocalDatastoreUtils'; import Storage from './Storage'; const LocalDatastoreController = { - async fromPinWithName(name: string): Array { + async fromPinWithName(name: string): Promise> { const values = await Storage.getItemAsync(name); if (!values) { return []; @@ -23,7 +23,7 @@ const LocalDatastoreController = { return Storage.removeItemAsync(name); }, - async getAllContents(): Object { + async getAllContents(): Promise { const keys = await Storage.getAllKeysAsync(); return keys.reduce(async (previousPromise, key) => { const LDS = await previousPromise; @@ -40,7 +40,7 @@ const LocalDatastoreController = { }, // Used for testing - async getRawStorage(): Object { + async getRawStorage(): Promise { const keys = await Storage.getAllKeysAsync(); return keys.reduce(async (previousPromise, key) => { const LDS = await previousPromise; @@ -50,7 +50,7 @@ const LocalDatastoreController = { }, Promise.resolve({})); }, - async clear(): Promise { + async clear(): Promise { const keys = await Storage.getAllKeysAsync(); const toRemove = []; @@ -65,3 +65,4 @@ const LocalDatastoreController = { }; module.exports = LocalDatastoreController; +export default LocalDatastoreController; \ No newline at end of file diff --git a/src/Parse.ts b/src/Parse.ts index 57269f6d4..7863ec793 100644 --- a/src/Parse.ts +++ b/src/Parse.ts @@ -47,7 +47,10 @@ interface ParseType { Parse?: ParseType, Analytics: typeof Analytics, AnonymousUtils: typeof AnonymousUtils, - Cloud: typeof Cloud, + Cloud: typeof Cloud & { + /** only availabe in server environments */ + useMasterKey?: () => void + }, CLP: typeof CLP, CoreManager: typeof CoreManager, Config: typeof Config, @@ -114,39 +117,39 @@ interface ParseType { const Parse: ParseType = { ACL: ACL, Analytics: Analytics, - AnonymousUtils: AnonymousUtils, + AnonymousUtils: AnonymousUtils, Cloud: Cloud, CLP: CLP, - CoreManager: CoreManager, - Config: Config, - Error: ParseError, - EventuallyQueue: EventuallyQueue, + CoreManager: CoreManager, + Config: Config, + Error: ParseError, + EventuallyQueue: EventuallyQueue, FacebookUtils: FacebookUtils, - File: File, - GeoPoint: GeoPoint, - Polygon: Polygon, - Installation: Installation, - LocalDatastore: LocalDatastore, - Object: Object, + File: File, + GeoPoint: GeoPoint, + Polygon: Polygon, + Installation: Installation, + LocalDatastore: LocalDatastore, + Object: Object, Op: { - Set: ParseOp.SetOp, - Unset: ParseOp.UnsetOp, - Increment: ParseOp.IncrementOp, - Add: ParseOp.AddOp, - Remove: ParseOp.RemoveOp, - AddUnique: ParseOp.AddUniqueOp, - Relation: ParseOp.RelationOp, - }, - Push: Push, - Query: Query, - Relation: Relation, - Role: Role, - Schema: Schema, - Session: Session, - Storage: Storage, - User: User, - LiveQueryClient: LiveQueryClient, - LiveQuery: undefined, + Set: ParseOp.SetOp, + Unset: ParseOp.UnsetOp, + Increment: ParseOp.IncrementOp, + Add: ParseOp.AddOp, + Remove: ParseOp.RemoveOp, + AddUnique: ParseOp.AddUniqueOp, + Relation: ParseOp.RelationOp, + }, + Push: Push, + Query: Query, + Relation: Relation, + Role: Role, + Schema: Schema, + Session: Session, + Storage: Storage, + User: User, + LiveQueryClient: LiveQueryClient, + LiveQuery: undefined, IndexedDB: undefined, Hooks: undefined, Parse: undefined, @@ -168,7 +171,7 @@ const Parse: ParseType = { /* eslint-disable no-console */ 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." + "node.js environment. You should require('parse/node') instead." ); /* eslint-enable no-console */ } @@ -361,7 +364,7 @@ const Parse: ParseType = { return encode(value, disallowObjects); }, - _getInstallationId () { + _getInstallationId() { return CoreManager.getInstallationController().currentInstallationId(); }, /** @@ -390,7 +393,7 @@ const Parse: ParseType = { * @static * @returns {boolean} */ - isLocalDatastoreEnabled () { + isLocalDatastoreEnabled() { return this.LocalDatastore.isEnabled; }, /** @@ -418,7 +421,7 @@ const Parse: ParseType = { * * @static */ - enableEncryptedUser () { + enableEncryptedUser() { this.encryptedUser = true; }, @@ -428,7 +431,7 @@ const Parse: ParseType = { * @static * @returns {boolean} */ - isEncryptedUserEnabled () { + isEncryptedUserEnabled() { return this.encryptedUser; }, }; @@ -439,7 +442,7 @@ CoreManager.setRESTController(RESTController); if (process.env.PARSE_BUILD === 'node') { Parse.initialize = Parse._initialize; - Parse.Cloud = Parse.Cloud || {}; + Parse.Cloud = Parse.Cloud || {} as any; Parse.Cloud.useMasterKey = function () { CoreManager.set('USE_MASTER_KEY', true); }; diff --git a/src/ParseQuery.ts b/src/ParseQuery.ts index 6639bfb66..3e6d5edf2 100644 --- a/src/ParseQuery.ts +++ b/src/ParseQuery.ts @@ -394,7 +394,7 @@ class ParseQuery { return '^' + quote(string); } - async _handleOfflineQuery(params: any) { + async _handleOfflineQuery(params: QueryJSON) { OfflineQuery.validateQuery(this); const localDatastore = CoreManager.getLocalDatastore(); const objects = await localDatastore._serializeObjectsFromPinName(this._localDatastorePinName); diff --git a/src/Storage.ts b/src/Storage.ts index 0af496743..bcbd094c9 100644 --- a/src/Storage.ts +++ b/src/Storage.ts @@ -4,6 +4,32 @@ import CoreManager from './CoreManager'; +export type StorageController = + | { + async: 0, + getItem: (path: string) => string | null, + setItem: (path: string, value: string) => void, + removeItem: (path: string) => void, + getItemAsync?: (path: string) => Promise, + setItemAsync?: (path: string, value: string) => Promise, + removeItemAsync?: (path: string) => Promise, + clear: () => void, + getAllKeys?: () => Array + getAllKeysAsync?: () => Promise> + } + | { + async: 1, + getItem?: (path: string) => string | null, + setItem?: (path: string, value: string) => void, + removeItem?: (path: string) => void, + getItemAsync: (path: string) => Promise, + setItemAsync: (path: string, value: string) => Promise, + removeItemAsync: (path: string) => Promise, + clear: () => void, + getAllKeys?: () => Array + getAllKeysAsync?: () => Promise> + }; + const Storage = { async(): boolean { const controller = CoreManager.getStorageController(); From 3ca292cd72aa812faf1c6bbdfa0af8f455bb0eba Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 08:23:37 +0700 Subject: [PATCH 16/27] added facebook types --- package-lock.json | 619 ++++++++++++++++++--- package.json | 1 + src/{FacebookUtils.js => FacebookUtils.ts} | 14 +- src/{OfflineQuery.js => OfflineQuery.ts} | 489 ++++++++-------- src/ParseUser.ts | 4 +- 5 files changed, 788 insertions(+), 339 deletions(-) rename src/{FacebookUtils.js => FacebookUtils.ts} (93%) rename src/{OfflineQuery.js => OfflineQuery.ts} (52%) diff --git a/package-lock.json b/package-lock.json index f3a7379fb..7f9d644c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,6 +35,7 @@ "@semantic-release/github": "8.0.7", "@semantic-release/npm": "9.0.2", "@semantic-release/release-notes-generator": "10.0.3", + "@types/facebook-js-sdk": "^3.3.9", "babel-jest": "29.5.0", "babel-plugin-inline-package-json": "2.0.0", "babel-plugin-minify-dead-code-elimination": "0.5.2", @@ -5049,6 +5050,12 @@ "@types/range-parser": "*" } }, + "node_modules/@types/facebook-js-sdk": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@types/facebook-js-sdk/-/facebook-js-sdk-3.3.9.tgz", + "integrity": "sha512-uJiJ+ljEPzC7jHGXl8YT7gRUh0fGzzJYrdwyrjgwSqFvrcCwlWMu/nLLcJeIRoFA81uVBwZBOKQIkjXFknXPsA==", + "dev": true + }, "node_modules/@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -19320,24 +19327,29 @@ }, "node_modules/npm/node_modules/@colors/colors": { "version": "1.5.0", + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.1.90" } }, "node_modules/npm/node_modules/@gar/promisify": { "version": "1.1.3", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/arborist": { "version": "5.6.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19387,6 +19399,7 @@ }, "node_modules/npm/node_modules/@npmcli/ci-detect": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19395,6 +19408,7 @@ }, "node_modules/npm/node_modules/@npmcli/config": { "version": "4.2.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19413,6 +19427,7 @@ }, "node_modules/npm/node_modules/@npmcli/disparity-colors": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19424,6 +19439,7 @@ }, "node_modules/npm/node_modules/@npmcli/fs": { "version": "2.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19436,6 +19452,7 @@ }, "node_modules/npm/node_modules/@npmcli/git": { "version": "3.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19455,6 +19472,7 @@ }, "node_modules/npm/node_modules/@npmcli/installed-package-contents": { "version": "1.0.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19470,6 +19488,7 @@ }, "node_modules/npm/node_modules/@npmcli/installed-package-contents/node_modules/npm-bundled": { "version": "1.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19478,6 +19497,7 @@ }, "node_modules/npm/node_modules/@npmcli/map-workspaces": { "version": "2.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19492,6 +19512,7 @@ }, "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { "version": "3.1.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19506,6 +19527,7 @@ }, "node_modules/npm/node_modules/@npmcli/move-file": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19518,11 +19540,13 @@ }, "node_modules/npm/node_modules/@npmcli/name-from-folder": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/@npmcli/node-gyp": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19531,6 +19555,7 @@ }, "node_modules/npm/node_modules/@npmcli/package-json": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19542,6 +19567,7 @@ }, "node_modules/npm/node_modules/@npmcli/promise-spawn": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19553,6 +19579,7 @@ }, "node_modules/npm/node_modules/@npmcli/query": { "version": "1.2.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19566,6 +19593,7 @@ }, "node_modules/npm/node_modules/@npmcli/run-script": { "version": "4.2.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19581,6 +19609,7 @@ }, "node_modules/npm/node_modules/@tootallnate/once": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19589,11 +19618,13 @@ }, "node_modules/npm/node_modules/abbrev": { "version": "1.1.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/agent-base": { "version": "6.0.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19605,6 +19636,7 @@ }, "node_modules/npm/node_modules/agentkeepalive": { "version": "4.2.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19618,6 +19650,7 @@ }, "node_modules/npm/node_modules/aggregate-error": { "version": "3.1.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19630,6 +19663,7 @@ }, "node_modules/npm/node_modules/ansi-regex": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19638,6 +19672,7 @@ }, "node_modules/npm/node_modules/ansi-styles": { "version": "4.3.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19652,16 +19687,19 @@ }, "node_modules/npm/node_modules/aproba": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/archy": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/are-we-there-yet": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19674,16 +19712,19 @@ }, "node_modules/npm/node_modules/asap": { "version": "2.0.6", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/balanced-match": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/bin-links": { "version": "3.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19700,6 +19741,7 @@ }, "node_modules/npm/node_modules/bin-links/node_modules/npm-normalize-package-bin": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19708,6 +19750,7 @@ }, "node_modules/npm/node_modules/binary-extensions": { "version": "2.2.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19716,6 +19759,7 @@ }, "node_modules/npm/node_modules/brace-expansion": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19724,6 +19768,7 @@ }, "node_modules/npm/node_modules/builtins": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19732,6 +19777,7 @@ }, "node_modules/npm/node_modules/cacache": { "version": "16.1.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19760,6 +19806,7 @@ }, "node_modules/npm/node_modules/chalk": { "version": "4.1.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19775,6 +19822,7 @@ }, "node_modules/npm/node_modules/chownr": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -19783,6 +19831,7 @@ }, "node_modules/npm/node_modules/cidr-regex": { "version": "3.1.1", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -19794,6 +19843,7 @@ }, "node_modules/npm/node_modules/clean-stack": { "version": "2.2.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19802,6 +19852,7 @@ }, "node_modules/npm/node_modules/cli-columns": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19814,6 +19865,7 @@ }, "node_modules/npm/node_modules/cli-table3": { "version": "0.6.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19828,6 +19880,7 @@ }, "node_modules/npm/node_modules/clone": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19836,6 +19889,7 @@ }, "node_modules/npm/node_modules/cmd-shim": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19847,6 +19901,7 @@ }, "node_modules/npm/node_modules/color-convert": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19858,11 +19913,13 @@ }, "node_modules/npm/node_modules/color-name": { "version": "1.1.4", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/color-support": { "version": "1.1.3", + "dev": true, "inBundle": true, "license": "ISC", "bin": { @@ -19871,6 +19928,7 @@ }, "node_modules/npm/node_modules/columnify": { "version": "1.6.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19883,21 +19941,25 @@ }, "node_modules/npm/node_modules/common-ancestor-path": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/concat-map": { "version": "0.0.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/console-control-strings": { "version": "1.1.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/cssesc": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "MIT", "bin": { @@ -19909,6 +19971,7 @@ }, "node_modules/npm/node_modules/debug": { "version": "4.3.4", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19925,11 +19988,13 @@ }, "node_modules/npm/node_modules/debug/node_modules/ms": { "version": "2.1.2", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/debuglog": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19938,6 +20003,7 @@ }, "node_modules/npm/node_modules/defaults": { "version": "1.0.3", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -19946,11 +20012,13 @@ }, "node_modules/npm/node_modules/delegates": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/depd": { "version": "1.1.2", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19959,6 +20027,7 @@ }, "node_modules/npm/node_modules/dezalgo": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -19968,6 +20037,7 @@ }, "node_modules/npm/node_modules/diff": { "version": "5.1.0", + "dev": true, "inBundle": true, "license": "BSD-3-Clause", "engines": { @@ -19976,19 +20046,23 @@ }, "node_modules/npm/node_modules/emoji-regex": { "version": "8.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/encoding": { "version": "0.1.13", + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "iconv-lite": "^0.6.2" } }, "node_modules/npm/node_modules/env-paths": { "version": "2.2.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -19997,16 +20071,19 @@ }, "node_modules/npm/node_modules/err-code": { "version": "2.0.3", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/fastest-levenshtein": { "version": "1.0.12", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/fs-minipass": { "version": "2.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20018,16 +20095,19 @@ }, "node_modules/npm/node_modules/fs.realpath": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/function-bind": { "version": "1.1.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/gauge": { "version": "4.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20046,6 +20126,7 @@ }, "node_modules/npm/node_modules/glob": { "version": "8.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20064,11 +20145,13 @@ }, "node_modules/npm/node_modules/graceful-fs": { "version": "4.2.10", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/has": { "version": "1.0.3", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20080,6 +20163,7 @@ }, "node_modules/npm/node_modules/has-flag": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20088,11 +20172,13 @@ }, "node_modules/npm/node_modules/has-unicode": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/hosted-git-info": { "version": "5.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20104,11 +20190,13 @@ }, "node_modules/npm/node_modules/http-cache-semantics": { "version": "4.1.0", + "dev": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/http-proxy-agent": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20122,6 +20210,7 @@ }, "node_modules/npm/node_modules/https-proxy-agent": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20134,6 +20223,7 @@ }, "node_modules/npm/node_modules/humanize-ms": { "version": "1.2.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20142,8 +20232,10 @@ }, "node_modules/npm/node_modules/iconv-lite": { "version": "0.6.3", + "dev": true, "inBundle": true, "license": "MIT", + "optional": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -20153,6 +20245,7 @@ }, "node_modules/npm/node_modules/ignore-walk": { "version": "5.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20164,6 +20257,7 @@ }, "node_modules/npm/node_modules/imurmurhash": { "version": "0.1.4", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20172,6 +20266,7 @@ }, "node_modules/npm/node_modules/indent-string": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20180,11 +20275,13 @@ }, "node_modules/npm/node_modules/infer-owner": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/inflight": { "version": "1.0.6", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20194,11 +20291,13 @@ }, "node_modules/npm/node_modules/inherits": { "version": "2.0.4", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/ini": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20207,6 +20306,7 @@ }, "node_modules/npm/node_modules/init-package-json": { "version": "3.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20224,11 +20324,13 @@ }, "node_modules/npm/node_modules/ip": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/ip-regex": { "version": "4.3.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20237,6 +20339,7 @@ }, "node_modules/npm/node_modules/is-cidr": { "version": "4.0.2", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -20248,6 +20351,7 @@ }, "node_modules/npm/node_modules/is-core-module": { "version": "2.10.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20259,6 +20363,7 @@ }, "node_modules/npm/node_modules/is-fullwidth-code-point": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20267,21 +20372,25 @@ }, "node_modules/npm/node_modules/is-lambda": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/isexe": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/json-parse-even-better-errors": { "version": "2.3.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/json-stringify-nice": { "version": "1.1.4", + "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -20290,6 +20399,7 @@ }, "node_modules/npm/node_modules/jsonparse": { "version": "1.3.1", + "dev": true, "engines": [ "node >= 0.2.0" ], @@ -20298,16 +20408,19 @@ }, "node_modules/npm/node_modules/just-diff": { "version": "5.1.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/just-diff-apply": { "version": "5.4.1", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/libnpmaccess": { "version": "6.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20322,6 +20435,7 @@ }, "node_modules/npm/node_modules/libnpmdiff": { "version": "4.0.5", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20340,6 +20454,7 @@ }, "node_modules/npm/node_modules/libnpmexec": { "version": "4.0.12", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20364,6 +20479,7 @@ }, "node_modules/npm/node_modules/libnpmfund": { "version": "3.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20375,6 +20491,7 @@ }, "node_modules/npm/node_modules/libnpmhook": { "version": "8.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20387,6 +20504,7 @@ }, "node_modules/npm/node_modules/libnpmorg": { "version": "4.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20399,6 +20517,7 @@ }, "node_modules/npm/node_modules/libnpmpack": { "version": "4.1.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20412,6 +20531,7 @@ }, "node_modules/npm/node_modules/libnpmpublish": { "version": "6.0.5", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20427,6 +20547,7 @@ }, "node_modules/npm/node_modules/libnpmsearch": { "version": "5.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20438,6 +20559,7 @@ }, "node_modules/npm/node_modules/libnpmteam": { "version": "4.0.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20450,6 +20572,7 @@ }, "node_modules/npm/node_modules/libnpmversion": { "version": "3.0.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20465,6 +20588,7 @@ }, "node_modules/npm/node_modules/lru-cache": { "version": "7.13.2", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20473,6 +20597,7 @@ }, "node_modules/npm/node_modules/make-fetch-happen": { "version": "10.2.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20499,6 +20624,7 @@ }, "node_modules/npm/node_modules/minimatch": { "version": "5.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20510,6 +20636,7 @@ }, "node_modules/npm/node_modules/minipass": { "version": "3.3.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20521,6 +20648,7 @@ }, "node_modules/npm/node_modules/minipass-collect": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20532,6 +20660,7 @@ }, "node_modules/npm/node_modules/minipass-fetch": { "version": "2.1.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20548,6 +20677,7 @@ }, "node_modules/npm/node_modules/minipass-flush": { "version": "1.0.5", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20559,6 +20689,7 @@ }, "node_modules/npm/node_modules/minipass-json-stream": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20568,6 +20699,7 @@ }, "node_modules/npm/node_modules/minipass-pipeline": { "version": "1.2.4", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20579,6 +20711,7 @@ }, "node_modules/npm/node_modules/minipass-sized": { "version": "1.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20590,6 +20723,7 @@ }, "node_modules/npm/node_modules/minizlib": { "version": "2.1.2", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20602,6 +20736,7 @@ }, "node_modules/npm/node_modules/mkdirp": { "version": "1.0.4", + "dev": true, "inBundle": true, "license": "MIT", "bin": { @@ -20613,6 +20748,7 @@ }, "node_modules/npm/node_modules/mkdirp-infer-owner": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20626,16 +20762,19 @@ }, "node_modules/npm/node_modules/ms": { "version": "2.1.3", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/mute-stream": { "version": "0.0.8", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/negotiator": { "version": "0.6.3", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20644,6 +20783,7 @@ }, "node_modules/npm/node_modules/node-gyp": { "version": "9.1.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20667,6 +20807,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20676,6 +20817,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/glob": { "version": "7.2.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20695,6 +20837,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/minimatch": { "version": "3.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20706,6 +20849,7 @@ }, "node_modules/npm/node_modules/node-gyp/node_modules/nopt": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20720,6 +20864,7 @@ }, "node_modules/npm/node_modules/nopt": { "version": "6.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20734,6 +20879,7 @@ }, "node_modules/npm/node_modules/normalize-package-data": { "version": "4.0.1", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -20748,6 +20894,7 @@ }, "node_modules/npm/node_modules/npm-audit-report": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20759,6 +20906,7 @@ }, "node_modules/npm/node_modules/npm-bundled": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20770,6 +20918,7 @@ }, "node_modules/npm/node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20778,6 +20927,7 @@ }, "node_modules/npm/node_modules/npm-install-checks": { "version": "5.0.0", + "dev": true, "inBundle": true, "license": "BSD-2-Clause", "dependencies": { @@ -20789,11 +20939,13 @@ }, "node_modules/npm/node_modules/npm-normalize-package-bin": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/npm-package-arg": { "version": "9.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20808,6 +20960,7 @@ }, "node_modules/npm/node_modules/npm-packlist": { "version": "5.1.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20825,6 +20978,7 @@ }, "node_modules/npm/node_modules/npm-packlist/node_modules/npm-normalize-package-bin": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20833,6 +20987,7 @@ }, "node_modules/npm/node_modules/npm-pick-manifest": { "version": "7.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20847,6 +21002,7 @@ }, "node_modules/npm/node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -20855,6 +21011,7 @@ }, "node_modules/npm/node_modules/npm-profile": { "version": "6.2.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20867,6 +21024,7 @@ }, "node_modules/npm/node_modules/npm-registry-fetch": { "version": "13.3.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20884,11 +21042,13 @@ }, "node_modules/npm/node_modules/npm-user-validate": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "BSD-2-Clause" }, "node_modules/npm/node_modules/npmlog": { "version": "6.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20903,6 +21063,7 @@ }, "node_modules/npm/node_modules/once": { "version": "1.4.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20911,6 +21072,7 @@ }, "node_modules/npm/node_modules/opener": { "version": "1.5.2", + "dev": true, "inBundle": true, "license": "(WTFPL OR MIT)", "bin": { @@ -20919,6 +21081,7 @@ }, "node_modules/npm/node_modules/p-map": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -20933,6 +21096,7 @@ }, "node_modules/npm/node_modules/pacote": { "version": "13.6.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20967,6 +21131,7 @@ }, "node_modules/npm/node_modules/parse-conflict-json": { "version": "2.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -20980,6 +21145,7 @@ }, "node_modules/npm/node_modules/path-is-absolute": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -20988,6 +21154,7 @@ }, "node_modules/npm/node_modules/postcss-selector-parser": { "version": "6.0.10", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21000,6 +21167,7 @@ }, "node_modules/npm/node_modules/proc-log": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21008,6 +21176,7 @@ }, "node_modules/npm/node_modules/promise-all-reject-late": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -21016,6 +21185,7 @@ }, "node_modules/npm/node_modules/promise-call-limit": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC", "funding": { @@ -21024,11 +21194,13 @@ }, "node_modules/npm/node_modules/promise-inflight": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21041,6 +21213,7 @@ }, "node_modules/npm/node_modules/promzard": { "version": "0.3.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21049,6 +21222,7 @@ }, "node_modules/npm/node_modules/qrcode-terminal": { "version": "0.12.0", + "dev": true, "inBundle": true, "bin": { "qrcode-terminal": "bin/qrcode-terminal.js" @@ -21056,6 +21230,7 @@ }, "node_modules/npm/node_modules/read": { "version": "1.0.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21067,6 +21242,7 @@ }, "node_modules/npm/node_modules/read-cmd-shim": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21075,6 +21251,7 @@ }, "node_modules/npm/node_modules/read-package-json": { "version": "5.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21089,6 +21266,7 @@ }, "node_modules/npm/node_modules/read-package-json-fast": { "version": "2.0.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21101,6 +21279,7 @@ }, "node_modules/npm/node_modules/read-package-json/node_modules/npm-normalize-package-bin": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21109,6 +21288,7 @@ }, "node_modules/npm/node_modules/readable-stream": { "version": "3.6.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21122,6 +21302,7 @@ }, "node_modules/npm/node_modules/readdir-scoped-modules": { "version": "1.1.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21133,6 +21314,7 @@ }, "node_modules/npm/node_modules/retry": { "version": "0.12.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -21141,6 +21323,7 @@ }, "node_modules/npm/node_modules/rimraf": { "version": "3.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21155,6 +21338,7 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/brace-expansion": { "version": "1.1.11", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21164,6 +21348,7 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/glob": { "version": "7.2.3", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21183,6 +21368,7 @@ }, "node_modules/npm/node_modules/rimraf/node_modules/minimatch": { "version": "3.1.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21194,6 +21380,7 @@ }, "node_modules/npm/node_modules/safe-buffer": { "version": "5.2.1", + "dev": true, "funding": [ { "type": "github", @@ -21213,11 +21400,14 @@ }, "node_modules/npm/node_modules/safer-buffer": { "version": "2.1.2", + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/npm/node_modules/semver": { "version": "7.3.7", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21232,6 +21422,7 @@ }, "node_modules/npm/node_modules/semver/node_modules/lru-cache": { "version": "6.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21243,16 +21434,19 @@ }, "node_modules/npm/node_modules/set-blocking": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/signal-exit": { "version": "3.0.7", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/smart-buffer": { "version": "4.2.0", + "dev": true, "inBundle": true, "license": "MIT", "engines": { @@ -21262,6 +21456,7 @@ }, "node_modules/npm/node_modules/socks": { "version": "2.7.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21275,6 +21470,7 @@ }, "node_modules/npm/node_modules/socks-proxy-agent": { "version": "7.0.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21288,6 +21484,7 @@ }, "node_modules/npm/node_modules/spdx-correct": { "version": "3.1.1", + "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -21297,11 +21494,13 @@ }, "node_modules/npm/node_modules/spdx-exceptions": { "version": "2.3.0", + "dev": true, "inBundle": true, "license": "CC-BY-3.0" }, "node_modules/npm/node_modules/spdx-expression-parse": { "version": "3.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21311,11 +21510,13 @@ }, "node_modules/npm/node_modules/spdx-license-ids": { "version": "3.0.11", + "dev": true, "inBundle": true, "license": "CC0-1.0" }, "node_modules/npm/node_modules/ssri": { "version": "9.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21327,6 +21528,7 @@ }, "node_modules/npm/node_modules/string_decoder": { "version": "1.3.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21335,6 +21537,7 @@ }, "node_modules/npm/node_modules/string-width": { "version": "4.2.3", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21348,6 +21551,7 @@ }, "node_modules/npm/node_modules/strip-ansi": { "version": "6.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21359,6 +21563,7 @@ }, "node_modules/npm/node_modules/supports-color": { "version": "7.2.0", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21370,6 +21575,7 @@ }, "node_modules/npm/node_modules/tar": { "version": "6.1.11", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21386,16 +21592,19 @@ }, "node_modules/npm/node_modules/text-table": { "version": "0.2.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/tiny-relative-date": { "version": "1.3.0", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/treeverse": { "version": "2.0.0", + "dev": true, "inBundle": true, "license": "ISC", "engines": { @@ -21404,6 +21613,7 @@ }, "node_modules/npm/node_modules/unique-filename": { "version": "2.0.1", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21415,6 +21625,7 @@ }, "node_modules/npm/node_modules/unique-slug": { "version": "3.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21426,11 +21637,13 @@ }, "node_modules/npm/node_modules/util-deprecate": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "MIT" }, "node_modules/npm/node_modules/validate-npm-package-license": { "version": "3.0.4", + "dev": true, "inBundle": true, "license": "Apache-2.0", "dependencies": { @@ -21440,6 +21653,7 @@ }, "node_modules/npm/node_modules/validate-npm-package-name": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21451,11 +21665,13 @@ }, "node_modules/npm/node_modules/walk-up-path": { "version": "1.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/wcwidth": { "version": "1.0.1", + "dev": true, "inBundle": true, "license": "MIT", "dependencies": { @@ -21464,6 +21680,7 @@ }, "node_modules/npm/node_modules/which": { "version": "2.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21478,6 +21695,7 @@ }, "node_modules/npm/node_modules/wide-align": { "version": "1.1.5", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21486,11 +21704,13 @@ }, "node_modules/npm/node_modules/wrappy": { "version": "1.0.2", + "dev": true, "inBundle": true, "license": "ISC" }, "node_modules/npm/node_modules/write-file-atomic": { "version": "4.0.2", + "dev": true, "inBundle": true, "license": "ISC", "dependencies": { @@ -21503,6 +21723,7 @@ }, "node_modules/npm/node_modules/yallist": { "version": "4.0.0", + "dev": true, "inBundle": true, "license": "ISC" }, @@ -31330,6 +31551,12 @@ "@types/range-parser": "*" } }, + "@types/facebook-js-sdk": { + "version": "3.3.9", + "resolved": "https://registry.npmjs.org/@types/facebook-js-sdk/-/facebook-js-sdk-3.3.9.tgz", + "integrity": "sha512-uJiJ+ljEPzC7jHGXl8YT7gRUh0fGzzJYrdwyrjgwSqFvrcCwlWMu/nLLcJeIRoFA81uVBwZBOKQIkjXFknXPsA==", + "dev": true + }, "@types/graceful-fs": { "version": "4.1.6", "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", @@ -42520,19 +42747,24 @@ "dependencies": { "@colors/colors": { "version": "1.5.0", - "bundled": true + "bundled": true, + "dev": true, + "optional": true }, "@gar/promisify": { "version": "1.1.3", - "bundled": true + "bundled": true, + "dev": true }, "@isaacs/string-locale-compare": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/arborist": { "version": "5.6.1", "bundled": true, + "dev": true, "requires": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -42574,11 +42806,13 @@ }, "@npmcli/ci-detect": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/config": { "version": "4.2.2", "bundled": true, + "dev": true, "requires": { "@npmcli/map-workspaces": "^2.0.2", "ini": "^3.0.0", @@ -42593,6 +42827,7 @@ "@npmcli/disparity-colors": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "ansi-styles": "^4.3.0" } @@ -42600,6 +42835,7 @@ "@npmcli/fs": { "version": "2.1.2", "bundled": true, + "dev": true, "requires": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" @@ -42608,6 +42844,7 @@ "@npmcli/git": { "version": "3.0.2", "bundled": true, + "dev": true, "requires": { "@npmcli/promise-spawn": "^3.0.0", "lru-cache": "^7.4.4", @@ -42623,6 +42860,7 @@ "@npmcli/installed-package-contents": { "version": "1.0.7", "bundled": true, + "dev": true, "requires": { "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" @@ -42631,6 +42869,7 @@ "npm-bundled": { "version": "1.1.2", "bundled": true, + "dev": true, "requires": { "npm-normalize-package-bin": "^1.0.1" } @@ -42640,6 +42879,7 @@ "@npmcli/map-workspaces": { "version": "2.0.4", "bundled": true, + "dev": true, "requires": { "@npmcli/name-from-folder": "^1.0.1", "glob": "^8.0.1", @@ -42650,6 +42890,7 @@ "@npmcli/metavuln-calculator": { "version": "3.1.1", "bundled": true, + "dev": true, "requires": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", @@ -42660,6 +42901,7 @@ "@npmcli/move-file": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -42667,15 +42909,18 @@ }, "@npmcli/name-from-folder": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/node-gyp": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "@npmcli/package-json": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.1" } @@ -42683,6 +42928,7 @@ "@npmcli/promise-spawn": { "version": "3.0.0", "bundled": true, + "dev": true, "requires": { "infer-owner": "^1.0.4" } @@ -42690,6 +42936,7 @@ "@npmcli/query": { "version": "1.2.0", "bundled": true, + "dev": true, "requires": { "npm-package-arg": "^9.1.0", "postcss-selector-parser": "^6.0.10", @@ -42699,6 +42946,7 @@ "@npmcli/run-script": { "version": "4.2.1", "bundled": true, + "dev": true, "requires": { "@npmcli/node-gyp": "^2.0.0", "@npmcli/promise-spawn": "^3.0.0", @@ -42709,15 +42957,18 @@ }, "@tootallnate/once": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "abbrev": { "version": "1.1.1", - "bundled": true + "bundled": true, + "dev": true }, "agent-base": { "version": "6.0.2", "bundled": true, + "dev": true, "requires": { "debug": "4" } @@ -42725,6 +42976,7 @@ "agentkeepalive": { "version": "4.2.1", "bundled": true, + "dev": true, "requires": { "debug": "^4.1.0", "depd": "^1.1.2", @@ -42734,6 +42986,7 @@ "aggregate-error": { "version": "3.1.0", "bundled": true, + "dev": true, "requires": { "clean-stack": "^2.0.0", "indent-string": "^4.0.0" @@ -42741,26 +42994,31 @@ }, "ansi-regex": { "version": "5.0.1", - "bundled": true + "bundled": true, + "dev": true }, "ansi-styles": { "version": "4.3.0", "bundled": true, + "dev": true, "requires": { "color-convert": "^2.0.1" } }, "aproba": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "archy": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "are-we-there-yet": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -42768,15 +43026,18 @@ }, "asap": { "version": "2.0.6", - "bundled": true + "bundled": true, + "dev": true }, "balanced-match": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "bin-links": { "version": "3.0.3", "bundled": true, + "dev": true, "requires": { "cmd-shim": "^5.0.0", "mkdirp-infer-owner": "^2.0.0", @@ -42788,17 +43049,20 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, "binary-extensions": { "version": "2.2.0", - "bundled": true + "bundled": true, + "dev": true }, "brace-expansion": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0" } @@ -42806,6 +43070,7 @@ "builtins": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "semver": "^7.0.0" } @@ -42813,6 +43078,7 @@ "cacache": { "version": "16.1.3", "bundled": true, + "dev": true, "requires": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", @@ -42837,6 +43103,7 @@ "chalk": { "version": "4.1.2", "bundled": true, + "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -42844,22 +43111,26 @@ }, "chownr": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "cidr-regex": { "version": "3.1.1", "bundled": true, + "dev": true, "requires": { "ip-regex": "^4.1.0" } }, "clean-stack": { "version": "2.2.0", - "bundled": true + "bundled": true, + "dev": true }, "cli-columns": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "string-width": "^4.2.3", "strip-ansi": "^6.0.1" @@ -42868,6 +43139,7 @@ "cli-table3": { "version": "0.6.2", "bundled": true, + "dev": true, "requires": { "@colors/colors": "1.5.0", "string-width": "^4.2.0" @@ -42875,11 +43147,13 @@ }, "clone": { "version": "1.0.4", - "bundled": true + "bundled": true, + "dev": true }, "cmd-shim": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "mkdirp-infer-owner": "^2.0.0" } @@ -42887,21 +43161,25 @@ "color-convert": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", - "bundled": true + "bundled": true, + "dev": true }, "color-support": { "version": "1.1.3", - "bundled": true + "bundled": true, + "dev": true }, "columnify": { "version": "1.6.0", "bundled": true, + "dev": true, "requires": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" @@ -42909,55 +43187,66 @@ }, "common-ancestor-path": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "concat-map": { "version": "0.0.1", - "bundled": true + "bundled": true, + "dev": true }, "console-control-strings": { "version": "1.1.0", - "bundled": true + "bundled": true, + "dev": true }, "cssesc": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "debug": { "version": "4.3.4", "bundled": true, + "dev": true, "requires": { "ms": "2.1.2" }, "dependencies": { "ms": { "version": "2.1.2", - "bundled": true + "bundled": true, + "dev": true } } }, "debuglog": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "defaults": { "version": "1.0.3", "bundled": true, + "dev": true, "requires": { "clone": "^1.0.2" } }, "delegates": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "depd": { "version": "1.1.2", - "bundled": true + "bundled": true, + "dev": true }, "dezalgo": { "version": "1.0.4", "bundled": true, + "dev": true, "requires": { "asap": "^2.0.0", "wrappy": "1" @@ -42965,49 +43254,60 @@ }, "diff": { "version": "5.1.0", - "bundled": true + "bundled": true, + "dev": true }, "emoji-regex": { "version": "8.0.0", - "bundled": true + "bundled": true, + "dev": true }, "encoding": { "version": "0.1.13", "bundled": true, + "dev": true, + "optional": true, "requires": { "iconv-lite": "^0.6.2" } }, "env-paths": { "version": "2.2.1", - "bundled": true + "bundled": true, + "dev": true }, "err-code": { "version": "2.0.3", - "bundled": true + "bundled": true, + "dev": true }, "fastest-levenshtein": { "version": "1.0.12", - "bundled": true + "bundled": true, + "dev": true }, "fs-minipass": { "version": "2.1.0", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } }, "fs.realpath": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "function-bind": { "version": "1.1.1", - "bundled": true + "bundled": true, + "dev": true }, "gauge": { "version": "4.0.4", "bundled": true, + "dev": true, "requires": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -43022,6 +43322,7 @@ "glob": { "version": "8.0.3", "bundled": true, + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -43032,37 +43333,44 @@ }, "graceful-fs": { "version": "4.2.10", - "bundled": true + "bundled": true, + "dev": true }, "has": { "version": "1.0.3", "bundled": true, + "dev": true, "requires": { "function-bind": "^1.1.1" } }, "has-flag": { "version": "4.0.0", - "bundled": true + "bundled": true, + "dev": true }, "has-unicode": { "version": "2.0.1", - "bundled": true + "bundled": true, + "dev": true }, "hosted-git-info": { "version": "5.1.0", "bundled": true, + "dev": true, "requires": { "lru-cache": "^7.5.1" } }, "http-cache-semantics": { "version": "4.1.0", - "bundled": true + "bundled": true, + "dev": true }, "http-proxy-agent": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "@tootallnate/once": "2", "agent-base": "6", @@ -43072,6 +43380,7 @@ "https-proxy-agent": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "agent-base": "6", "debug": "4" @@ -43080,6 +43389,7 @@ "humanize-ms": { "version": "1.2.1", "bundled": true, + "dev": true, "requires": { "ms": "^2.0.0" } @@ -43087,6 +43397,8 @@ "iconv-lite": { "version": "0.6.3", "bundled": true, + "dev": true, + "optional": true, "requires": { "safer-buffer": ">= 2.1.2 < 3.0.0" } @@ -43094,25 +43406,30 @@ "ignore-walk": { "version": "5.0.1", "bundled": true, + "dev": true, "requires": { "minimatch": "^5.0.1" } }, "imurmurhash": { "version": "0.1.4", - "bundled": true + "bundled": true, + "dev": true }, "indent-string": { "version": "4.0.0", - "bundled": true + "bundled": true, + "dev": true }, "infer-owner": { "version": "1.0.4", - "bundled": true + "bundled": true, + "dev": true }, "inflight": { "version": "1.0.6", "bundled": true, + "dev": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -43120,15 +43437,18 @@ }, "inherits": { "version": "2.0.4", - "bundled": true + "bundled": true, + "dev": true }, "ini": { "version": "3.0.1", - "bundled": true + "bundled": true, + "dev": true }, "init-package-json": { "version": "3.0.2", "bundled": true, + "dev": true, "requires": { "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", @@ -43141,15 +43461,18 @@ }, "ip": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "ip-regex": { "version": "4.3.0", - "bundled": true + "bundled": true, + "dev": true }, "is-cidr": { "version": "4.0.2", "bundled": true, + "dev": true, "requires": { "cidr-regex": "^3.1.1" } @@ -43157,45 +43480,55 @@ "is-core-module": { "version": "2.10.0", "bundled": true, + "dev": true, "requires": { "has": "^1.0.3" } }, "is-fullwidth-code-point": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "is-lambda": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "isexe": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "json-parse-even-better-errors": { "version": "2.3.1", - "bundled": true + "bundled": true, + "dev": true }, "json-stringify-nice": { "version": "1.1.4", - "bundled": true + "bundled": true, + "dev": true }, "jsonparse": { "version": "1.3.1", - "bundled": true + "bundled": true, + "dev": true }, "just-diff": { "version": "5.1.1", - "bundled": true + "bundled": true, + "dev": true }, "just-diff-apply": { "version": "5.4.1", - "bundled": true + "bundled": true, + "dev": true }, "libnpmaccess": { "version": "6.0.4", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "minipass": "^3.1.1", @@ -43206,6 +43539,7 @@ "libnpmdiff": { "version": "4.0.5", "bundled": true, + "dev": true, "requires": { "@npmcli/disparity-colors": "^2.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -43220,6 +43554,7 @@ "libnpmexec": { "version": "4.0.12", "bundled": true, + "dev": true, "requires": { "@npmcli/arborist": "^5.6.1", "@npmcli/ci-detect": "^2.0.0", @@ -43240,6 +43575,7 @@ "libnpmfund": { "version": "3.0.3", "bundled": true, + "dev": true, "requires": { "@npmcli/arborist": "^5.6.1" } @@ -43247,6 +43583,7 @@ "libnpmhook": { "version": "8.0.4", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -43255,6 +43592,7 @@ "libnpmorg": { "version": "4.0.4", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -43263,6 +43601,7 @@ "libnpmpack": { "version": "4.1.3", "bundled": true, + "dev": true, "requires": { "@npmcli/run-script": "^4.1.3", "npm-package-arg": "^9.0.1", @@ -43272,6 +43611,7 @@ "libnpmpublish": { "version": "6.0.5", "bundled": true, + "dev": true, "requires": { "normalize-package-data": "^4.0.0", "npm-package-arg": "^9.0.1", @@ -43283,6 +43623,7 @@ "libnpmsearch": { "version": "5.0.4", "bundled": true, + "dev": true, "requires": { "npm-registry-fetch": "^13.0.0" } @@ -43290,6 +43631,7 @@ "libnpmteam": { "version": "4.0.4", "bundled": true, + "dev": true, "requires": { "aproba": "^2.0.0", "npm-registry-fetch": "^13.0.0" @@ -43298,6 +43640,7 @@ "libnpmversion": { "version": "3.0.7", "bundled": true, + "dev": true, "requires": { "@npmcli/git": "^3.0.0", "@npmcli/run-script": "^4.1.3", @@ -43308,11 +43651,13 @@ }, "lru-cache": { "version": "7.13.2", - "bundled": true + "bundled": true, + "dev": true }, "make-fetch-happen": { "version": "10.2.1", "bundled": true, + "dev": true, "requires": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -43335,6 +43680,7 @@ "minimatch": { "version": "5.1.0", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^2.0.1" } @@ -43342,6 +43688,7 @@ "minipass": { "version": "3.3.4", "bundled": true, + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -43349,6 +43696,7 @@ "minipass-collect": { "version": "1.0.2", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43356,6 +43704,7 @@ "minipass-fetch": { "version": "2.1.1", "bundled": true, + "dev": true, "requires": { "encoding": "^0.1.13", "minipass": "^3.1.6", @@ -43366,6 +43715,7 @@ "minipass-flush": { "version": "1.0.5", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43373,6 +43723,7 @@ "minipass-json-stream": { "version": "1.0.1", "bundled": true, + "dev": true, "requires": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -43381,6 +43732,7 @@ "minipass-pipeline": { "version": "1.2.4", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43388,6 +43740,7 @@ "minipass-sized": { "version": "1.0.3", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0" } @@ -43395,6 +43748,7 @@ "minizlib": { "version": "2.1.2", "bundled": true, + "dev": true, "requires": { "minipass": "^3.0.0", "yallist": "^4.0.0" @@ -43402,11 +43756,13 @@ }, "mkdirp": { "version": "1.0.4", - "bundled": true + "bundled": true, + "dev": true }, "mkdirp-infer-owner": { "version": "2.0.0", "bundled": true, + "dev": true, "requires": { "chownr": "^2.0.0", "infer-owner": "^1.0.4", @@ -43415,19 +43771,23 @@ }, "ms": { "version": "2.1.3", - "bundled": true + "bundled": true, + "dev": true }, "mute-stream": { "version": "0.0.8", - "bundled": true + "bundled": true, + "dev": true }, "negotiator": { "version": "0.6.3", - "bundled": true + "bundled": true, + "dev": true }, "node-gyp": { "version": "9.1.0", "bundled": true, + "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -43444,6 +43804,7 @@ "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -43452,6 +43813,7 @@ "glob": { "version": "7.2.3", "bundled": true, + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -43464,6 +43826,7 @@ "minimatch": { "version": "3.1.2", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -43471,6 +43834,7 @@ "nopt": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "abbrev": "1" } @@ -43480,6 +43844,7 @@ "nopt": { "version": "6.0.0", "bundled": true, + "dev": true, "requires": { "abbrev": "^1.0.0" } @@ -43487,6 +43852,7 @@ "normalize-package-data": { "version": "4.0.1", "bundled": true, + "dev": true, "requires": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -43497,6 +43863,7 @@ "npm-audit-report": { "version": "3.0.0", "bundled": true, + "dev": true, "requires": { "chalk": "^4.0.0" } @@ -43504,30 +43871,35 @@ "npm-bundled": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "npm-normalize-package-bin": "^2.0.0" }, "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, "npm-install-checks": { "version": "5.0.0", "bundled": true, + "dev": true, "requires": { "semver": "^7.1.1" } }, "npm-normalize-package-bin": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "npm-package-arg": { "version": "9.1.0", "bundled": true, + "dev": true, "requires": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -43538,6 +43910,7 @@ "npm-packlist": { "version": "5.1.3", "bundled": true, + "dev": true, "requires": { "glob": "^8.0.1", "ignore-walk": "^5.0.1", @@ -43547,13 +43920,15 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, "npm-pick-manifest": { "version": "7.0.2", "bundled": true, + "dev": true, "requires": { "npm-install-checks": "^5.0.0", "npm-normalize-package-bin": "^2.0.0", @@ -43563,13 +43938,15 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, "npm-profile": { "version": "6.2.1", "bundled": true, + "dev": true, "requires": { "npm-registry-fetch": "^13.0.1", "proc-log": "^2.0.0" @@ -43578,6 +43955,7 @@ "npm-registry-fetch": { "version": "13.3.1", "bundled": true, + "dev": true, "requires": { "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", @@ -43590,11 +43968,13 @@ }, "npm-user-validate": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "npmlog": { "version": "6.0.2", "bundled": true, + "dev": true, "requires": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -43605,17 +43985,20 @@ "once": { "version": "1.4.0", "bundled": true, + "dev": true, "requires": { "wrappy": "1" } }, "opener": { "version": "1.5.2", - "bundled": true + "bundled": true, + "dev": true }, "p-map": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "aggregate-error": "^3.0.0" } @@ -43623,6 +44006,7 @@ "pacote": { "version": "13.6.2", "bundled": true, + "dev": true, "requires": { "@npmcli/git": "^3.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -43650,6 +44034,7 @@ "parse-conflict-json": { "version": "2.0.2", "bundled": true, + "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.1", "just-diff": "^5.0.1", @@ -43658,11 +44043,13 @@ }, "path-is-absolute": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "postcss-selector-parser": { "version": "6.0.10", "bundled": true, + "dev": true, "requires": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -43670,23 +44057,28 @@ }, "proc-log": { "version": "2.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-all-reject-late": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-call-limit": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-inflight": { "version": "1.0.1", - "bundled": true + "bundled": true, + "dev": true }, "promise-retry": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -43695,28 +44087,33 @@ "promzard": { "version": "0.3.0", "bundled": true, + "dev": true, "requires": { "read": "1" } }, "qrcode-terminal": { "version": "0.12.0", - "bundled": true + "bundled": true, + "dev": true }, "read": { "version": "1.0.7", "bundled": true, + "dev": true, "requires": { "mute-stream": "~0.0.4" } }, "read-cmd-shim": { "version": "3.0.0", - "bundled": true + "bundled": true, + "dev": true }, "read-package-json": { "version": "5.0.2", "bundled": true, + "dev": true, "requires": { "glob": "^8.0.1", "json-parse-even-better-errors": "^2.3.1", @@ -43726,13 +44123,15 @@ "dependencies": { "npm-normalize-package-bin": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, "read-package-json-fast": { "version": "2.0.3", "bundled": true, + "dev": true, "requires": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" @@ -43741,6 +44140,7 @@ "readable-stream": { "version": "3.6.0", "bundled": true, + "dev": true, "requires": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -43750,6 +44150,7 @@ "readdir-scoped-modules": { "version": "1.1.0", "bundled": true, + "dev": true, "requires": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -43759,11 +44160,13 @@ }, "retry": { "version": "0.12.0", - "bundled": true + "bundled": true, + "dev": true }, "rimraf": { "version": "3.0.2", "bundled": true, + "dev": true, "requires": { "glob": "^7.1.3" }, @@ -43771,6 +44174,7 @@ "brace-expansion": { "version": "1.1.11", "bundled": true, + "dev": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -43779,6 +44183,7 @@ "glob": { "version": "7.2.3", "bundled": true, + "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -43791,6 +44196,7 @@ "minimatch": { "version": "3.1.2", "bundled": true, + "dev": true, "requires": { "brace-expansion": "^1.1.7" } @@ -43799,15 +44205,19 @@ }, "safe-buffer": { "version": "5.2.1", - "bundled": true + "bundled": true, + "dev": true }, "safer-buffer": { "version": "2.1.2", - "bundled": true + "bundled": true, + "dev": true, + "optional": true }, "semver": { "version": "7.3.7", "bundled": true, + "dev": true, "requires": { "lru-cache": "^6.0.0" }, @@ -43815,6 +44225,7 @@ "lru-cache": { "version": "6.0.0", "bundled": true, + "dev": true, "requires": { "yallist": "^4.0.0" } @@ -43823,19 +44234,23 @@ }, "set-blocking": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "signal-exit": { "version": "3.0.7", - "bundled": true + "bundled": true, + "dev": true }, "smart-buffer": { "version": "4.2.0", - "bundled": true + "bundled": true, + "dev": true }, "socks": { "version": "2.7.0", "bundled": true, + "dev": true, "requires": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -43844,6 +44259,7 @@ "socks-proxy-agent": { "version": "7.0.0", "bundled": true, + "dev": true, "requires": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -43853,6 +44269,7 @@ "spdx-correct": { "version": "3.1.1", "bundled": true, + "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -43860,11 +44277,13 @@ }, "spdx-exceptions": { "version": "2.3.0", - "bundled": true + "bundled": true, + "dev": true }, "spdx-expression-parse": { "version": "3.0.1", "bundled": true, + "dev": true, "requires": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -43872,11 +44291,13 @@ }, "spdx-license-ids": { "version": "3.0.11", - "bundled": true + "bundled": true, + "dev": true }, "ssri": { "version": "9.0.1", "bundled": true, + "dev": true, "requires": { "minipass": "^3.1.1" } @@ -43884,6 +44305,7 @@ "string_decoder": { "version": "1.3.0", "bundled": true, + "dev": true, "requires": { "safe-buffer": "~5.2.0" } @@ -43891,6 +44313,7 @@ "string-width": { "version": "4.2.3", "bundled": true, + "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -43900,6 +44323,7 @@ "strip-ansi": { "version": "6.0.1", "bundled": true, + "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -43907,6 +44331,7 @@ "supports-color": { "version": "7.2.0", "bundled": true, + "dev": true, "requires": { "has-flag": "^4.0.0" } @@ -43914,6 +44339,7 @@ "tar": { "version": "6.1.11", "bundled": true, + "dev": true, "requires": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", @@ -43925,19 +44351,23 @@ }, "text-table": { "version": "0.2.0", - "bundled": true + "bundled": true, + "dev": true }, "tiny-relative-date": { "version": "1.3.0", - "bundled": true + "bundled": true, + "dev": true }, "treeverse": { "version": "2.0.0", - "bundled": true + "bundled": true, + "dev": true }, "unique-filename": { "version": "2.0.1", "bundled": true, + "dev": true, "requires": { "unique-slug": "^3.0.0" } @@ -43945,17 +44375,20 @@ "unique-slug": { "version": "3.0.0", "bundled": true, + "dev": true, "requires": { "imurmurhash": "^0.1.4" } }, "util-deprecate": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "validate-npm-package-license": { "version": "3.0.4", "bundled": true, + "dev": true, "requires": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -43964,17 +44397,20 @@ "validate-npm-package-name": { "version": "4.0.0", "bundled": true, + "dev": true, "requires": { "builtins": "^5.0.0" } }, "walk-up-path": { "version": "1.0.0", - "bundled": true + "bundled": true, + "dev": true }, "wcwidth": { "version": "1.0.1", "bundled": true, + "dev": true, "requires": { "defaults": "^1.0.3" } @@ -43982,6 +44418,7 @@ "which": { "version": "2.0.2", "bundled": true, + "dev": true, "requires": { "isexe": "^2.0.0" } @@ -43989,17 +44426,20 @@ "wide-align": { "version": "1.1.5", "bundled": true, + "dev": true, "requires": { "string-width": "^1.0.2 || 2 || 3 || 4" } }, "wrappy": { "version": "1.0.2", - "bundled": true + "bundled": true, + "dev": true }, "write-file-atomic": { "version": "4.0.2", "bundled": true, + "dev": true, "requires": { "imurmurhash": "^0.1.4", "signal-exit": "^3.0.7" @@ -44007,7 +44447,8 @@ }, "yallist": { "version": "4.0.0", - "bundled": true + "bundled": true, + "dev": true } } }, diff --git a/package.json b/package.json index 90b0a6de4..205674490 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@semantic-release/github": "8.0.7", "@semantic-release/npm": "9.0.2", "@semantic-release/release-notes-generator": "10.0.3", + "@types/facebook-js-sdk": "^3.3.9", "babel-jest": "29.5.0", "babel-plugin-inline-package-json": "2.0.0", "babel-plugin-minify-dead-code-elimination": "0.5.2", diff --git a/src/FacebookUtils.js b/src/FacebookUtils.ts similarity index 93% rename from src/FacebookUtils.js rename to src/FacebookUtils.ts index d7ca36b2a..4020fe2ae 100644 --- a/src/FacebookUtils.js +++ b/src/FacebookUtils.ts @@ -3,11 +3,13 @@ */ /* global FB */ import ParseUser from './ParseUser'; +import type { AuthProviderType } from './ParseUser'; +import '@types/facebook-js-sdk' let initialized = false; let requestedPermissions; let initOptions; -const provider = { +const provider: AuthProviderType = { authenticate(options) { if (typeof FB === 'undefined') { options.error(this, 'Facebook SDK not found.'); @@ -38,7 +40,7 @@ const provider = { restoreAuthentication(authData) { if (authData) { - const newOptions = {}; + const newOptions: typeof initOptions = {}; if (initOptions) { for (const key in initOptions) { newOptions[key] = initOptions[key]; @@ -107,13 +109,13 @@ const FacebookUtils = { } } if (initOptions.status && typeof console !== 'undefined') { - const warn = console.warn || console.log || function () {}; // eslint-disable-line no-console + const warn = console.warn || console.log || function () { }; // eslint-disable-line no-console 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.' + ' 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; diff --git a/src/OfflineQuery.js b/src/OfflineQuery.ts similarity index 52% rename from src/OfflineQuery.js rename to src/OfflineQuery.ts index efbc200c9..5a1e842ce 100644 --- a/src/OfflineQuery.js +++ b/src/OfflineQuery.ts @@ -1,8 +1,13 @@ -const equalObjects = require('./equals').default; -const decode = require('./decode').default; -const ParseError = require('./ParseError').default; -const ParsePolygon = require('./ParsePolygon').default; -const ParseGeoPoint = require('./ParseGeoPoint').default; +import { AttributeMap } from "./ObjectStateMutations"; +import type ParseObject from "./ParseObject"; +import type Query from "./ParseQuery"; +import type { QueryJSON, WhereClause } from './ParseQuery'; + +import equalObjects from './equals'; +import decode from './decode'; +import ParseError from './ParseError'; +import ParsePolygon from './ParsePolygon'; +import ParseGeoPoint from './ParseGeoPoint'; /** * contains -- Determines if an object is contained in a list with special handling for Parse pointers. * @@ -11,7 +16,7 @@ const ParseGeoPoint = require('./ParseGeoPoint').default; * @private * @returns {boolean} */ -function contains(haystack, needle) { +function contains(haystack: any[], needle: any) { if (needle && needle.__type && (needle.__type === 'Pointer' || needle.__type === 'Object')) { for (const i in haystack) { const ptr = haystack[i]; @@ -54,11 +59,11 @@ function transformObject(object) { * @private * @returns {boolean} */ -function matchesQuery(className, object, objects, query) { +function matchesQuery(className: string, object: ParseObject, objects: ParseObject[], query: WhereClause) { if (object.className !== className) { return false; } - let obj = object; + let obj: AttributeMap | ParseObject = object; let q = query; if (object.toJSON) { obj = object.toJSON(); @@ -160,52 +165,52 @@ function relativeTimeToDate(text, now = new Date()) { } switch (interval) { - case 'yr': - case 'yrs': - case 'year': - case 'years': - seconds += val * 31536000; // 365 * 24 * 60 * 60 - break; - - case 'wk': - case 'wks': - case 'week': - case 'weeks': - seconds += val * 604800; // 7 * 24 * 60 * 60 - break; - - case 'd': - case 'day': - case 'days': - seconds += val * 86400; // 24 * 60 * 60 - break; - - case 'hr': - case 'hrs': - case 'hour': - case 'hours': - seconds += val * 3600; // 60 * 60 - break; - - case 'min': - case 'mins': - case 'minute': - case 'minutes': - seconds += val * 60; - break; - - case 'sec': - case 'secs': - case 'second': - case 'seconds': - seconds += val; - break; - - default: - return { - status: 'error', - info: `Invalid interval: '${interval}'`, - }; + case 'yr': + case 'yrs': + case 'year': + case 'years': + seconds += val * 31536000; // 365 * 24 * 60 * 60 + break; + + case 'wk': + case 'wks': + case 'week': + case 'weeks': + seconds += val * 604800; // 7 * 24 * 60 * 60 + break; + + case 'd': + case 'day': + case 'days': + seconds += val * 86400; // 24 * 60 * 60 + break; + + case 'hr': + case 'hrs': + case 'hour': + case 'hours': + seconds += val * 3600; // 60 * 60 + break; + + case 'min': + case 'mins': + case 'minute': + case 'minutes': + seconds += val * 60; + break; + + case 'sec': + case 'secs': + case 'second': + case 'seconds': + seconds += val; + break; + + default: + return { + status: 'error', + info: `Invalid interval: '${interval}'`, + }; } } @@ -333,229 +338,229 @@ function matchesKeyConstraints(className, object, objects, key, constraints) { if ( toString.call(compareTo) === '[object Date]' || (typeof compareTo === 'string' && - new Date(compareTo) !== 'Invalid Date' && - !isNaN(new Date(compareTo))) + new Date(compareTo).toString() !== 'Invalid Date' && + !isNaN(new Date(compareTo).getTime())) ) { object[key] = new Date(object[key].iso ? object[key].iso : object[key]); } switch (condition) { - case '$lt': - if (object[key] >= compareTo) { - return false; - } - break; - case '$lte': - if (object[key] > compareTo) { - return false; - } - break; - case '$gt': - if (object[key] <= compareTo) { - return false; - } - break; - case '$gte': - if (object[key] < compareTo) { - return false; - } - break; - case '$ne': - if (equalObjects(object[key], compareTo)) { - return false; - } - break; - case '$in': - if (!contains(compareTo, object[key])) { - return false; - } - break; - case '$nin': - if (contains(compareTo, object[key])) { - return false; - } - break; - case '$all': - for (i = 0; i < compareTo.length; i++) { - if (object[key].indexOf(compareTo[i]) < 0) { + case '$lt': + if (object[key] >= compareTo) { return false; } - } - break; - case '$exists': { - const propertyExists = typeof object[key] !== 'undefined'; - const existenceIsRequired = constraints['$exists']; - if (typeof constraints['$exists'] !== 'boolean') { - // The SDK will never submit a non-boolean for $exists, but if someone - // tries to submit a non-boolean for $exits outside the SDKs, just ignore it. break; - } - if ((!propertyExists && existenceIsRequired) || (propertyExists && !existenceIsRequired)) { - return false; - } - break; - } - case '$regex': { - if (typeof compareTo === 'object') { - return compareTo.test(object[key]); - } - // JS doesn't support perl-style escaping - let expString = ''; - let escapeEnd = -2; - let escapeStart = compareTo.indexOf('\\Q'); - while (escapeStart > -1) { - // Add the unescaped portion - expString += compareTo.substring(escapeEnd + 2, escapeStart); - escapeEnd = compareTo.indexOf('\\E', escapeStart); - if (escapeEnd > -1) { - expString += compareTo - .substring(escapeStart + 2, escapeEnd) - .replace(/\\\\\\\\E/g, '\\E') - .replace(/\W/g, '\\$&'); + case '$lte': + if (object[key] > compareTo) { + return false; } - - escapeStart = compareTo.indexOf('\\Q', escapeEnd); - } - expString += compareTo.substring(Math.max(escapeStart, escapeEnd + 2)); - let modifiers = constraints.$options || ''; - modifiers = modifiers.replace('x', '').replace('s', ''); - // Parse Server / Mongo support x and s modifiers but JS RegExp doesn't - const exp = new RegExp(expString, modifiers); - if (!exp.test(object[key])) { - return false; - } - break; - } - case '$nearSphere': { - if (!compareTo || !object[key]) { - return false; + break; + case '$gt': + if (object[key] <= compareTo) { + return false; + } + break; + case '$gte': + if (object[key] < compareTo) { + return false; + } + break; + case '$ne': + if (equalObjects(object[key], compareTo)) { + return false; + } + break; + case '$in': + if (!contains(compareTo, object[key])) { + return false; + } + break; + case '$nin': + if (contains(compareTo, object[key])) { + return false; + } + break; + case '$all': + for (i = 0; i < compareTo.length; i++) { + if (object[key].indexOf(compareTo[i]) < 0) { + return false; + } + } + break; + case '$exists': { + const propertyExists = typeof object[key] !== 'undefined'; + const existenceIsRequired = constraints['$exists']; + if (typeof constraints['$exists'] !== 'boolean') { + // The SDK will never submit a non-boolean for $exists, but if someone + // tries to submit a non-boolean for $exits outside the SDKs, just ignore it. + break; + } + if ((!propertyExists && existenceIsRequired) || (propertyExists && !existenceIsRequired)) { + return false; + } + break; } - const distance = compareTo.radiansTo(object[key]); - const max = constraints.$maxDistance || Infinity; - return distance <= max; - } - case '$within': { - if (!compareTo || !object[key]) { - return false; + case '$regex': { + if (typeof compareTo === 'object') { + return compareTo.test(object[key]); + } + // JS doesn't support perl-style escaping + let expString = ''; + let escapeEnd = -2; + let escapeStart = compareTo.indexOf('\\Q'); + while (escapeStart > -1) { + // Add the unescaped portion + expString += compareTo.substring(escapeEnd + 2, escapeStart); + escapeEnd = compareTo.indexOf('\\E', escapeStart); + if (escapeEnd > -1) { + expString += compareTo + .substring(escapeStart + 2, escapeEnd) + .replace(/\\\\\\\\E/g, '\\E') + .replace(/\W/g, '\\$&'); + } + + escapeStart = compareTo.indexOf('\\Q', escapeEnd); + } + expString += compareTo.substring(Math.max(escapeStart, escapeEnd + 2)); + let modifiers = constraints.$options || ''; + modifiers = modifiers.replace('x', '').replace('s', ''); + // Parse Server / Mongo support x and s modifiers but JS RegExp doesn't + const exp = new RegExp(expString, modifiers); + if (!exp.test(object[key])) { + return false; + } + break; } - const southWest = compareTo.$box[0]; - const northEast = compareTo.$box[1]; - if (southWest.latitude > northEast.latitude || southWest.longitude > northEast.longitude) { - // Invalid box, crosses the date line - return false; + case '$nearSphere': { + if (!compareTo || !object[key]) { + return false; + } + const distance = compareTo.radiansTo(object[key]); + const max = constraints.$maxDistance || Infinity; + return distance <= max; } - return ( - object[key].latitude > southWest.latitude && + case '$within': { + if (!compareTo || !object[key]) { + return false; + } + const southWest = compareTo.$box[0]; + const northEast = compareTo.$box[1]; + if (southWest.latitude > northEast.latitude || southWest.longitude > northEast.longitude) { + // Invalid box, crosses the date line + return false; + } + return ( + object[key].latitude > southWest.latitude && object[key].latitude < northEast.latitude && object[key].longitude > southWest.longitude && object[key].longitude < northEast.longitude - ); - } - case '$options': - // Not a query type, but a way to add options to $regex. Ignore and - // avoid the default - break; - case '$maxDistance': - // Not a query type, but a way to add a cap to $nearSphere. Ignore and - // avoid the default - break; - case '$select': { - const subQueryObjects = objects.filter((obj, index, arr) => { - return matchesQuery(compareTo.query.className, obj, arr, compareTo.query.where); - }); - for (let i = 0; i < subQueryObjects.length; i += 1) { - const subObject = transformObject(subQueryObjects[i]); - return equalObjects(object[key], subObject[compareTo.key]); + ); } - return false; - } - case '$dontSelect': { - const subQueryObjects = objects.filter((obj, index, arr) => { - return matchesQuery(compareTo.query.className, obj, arr, compareTo.query.where); - }); - for (let i = 0; i < subQueryObjects.length; i += 1) { - const subObject = transformObject(subQueryObjects[i]); - return !equalObjects(object[key], subObject[compareTo.key]); + case '$options': + // Not a query type, but a way to add options to $regex. Ignore and + // avoid the default + break; + case '$maxDistance': + // Not a query type, but a way to add a cap to $nearSphere. Ignore and + // avoid the default + break; + case '$select': { + const subQueryObjects = objects.filter((obj, index, arr) => { + return matchesQuery(compareTo.query.className, obj, arr, compareTo.query.where); + }); + for (let i = 0; i < subQueryObjects.length; i += 1) { + const subObject = transformObject(subQueryObjects[i]); + return equalObjects(object[key], subObject[compareTo.key]); + } + return false; } - return false; - } - case '$inQuery': { - const subQueryObjects = objects.filter((obj, index, arr) => { - return matchesQuery(compareTo.className, obj, arr, compareTo.where); - }); + case '$dontSelect': { + const subQueryObjects = objects.filter((obj, index, arr) => { + return matchesQuery(compareTo.query.className, obj, arr, compareTo.query.where); + }); + for (let i = 0; i < subQueryObjects.length; i += 1) { + const subObject = transformObject(subQueryObjects[i]); + return !equalObjects(object[key], subObject[compareTo.key]); + } + return false; + } + case '$inQuery': { + const subQueryObjects = objects.filter((obj, index, arr) => { + return matchesQuery(compareTo.className, obj, arr, compareTo.where); + }); - for (let i = 0; i < subQueryObjects.length; i += 1) { - const subObject = transformObject(subQueryObjects[i]); - if ( - object[key].className === subObject.className && + for (let i = 0; i < subQueryObjects.length; i += 1) { + const subObject = transformObject(subQueryObjects[i]); + if ( + object[key].className === subObject.className && object[key].objectId === subObject.objectId - ) { - return true; + ) { + return true; + } } + return false; } - return false; - } - case '$notInQuery': { - const subQueryObjects = objects.filter((obj, index, arr) => { - return matchesQuery(compareTo.className, obj, arr, compareTo.where); - }); + case '$notInQuery': { + const subQueryObjects = objects.filter((obj, index, arr) => { + return matchesQuery(compareTo.className, obj, arr, compareTo.where); + }); - for (let i = 0; i < subQueryObjects.length; i += 1) { - const subObject = transformObject(subQueryObjects[i]); - if ( - object[key].className === subObject.className && + for (let i = 0; i < subQueryObjects.length; i += 1) { + const subObject = transformObject(subQueryObjects[i]); + if ( + object[key].className === subObject.className && object[key].objectId === subObject.objectId - ) { - return false; + ) { + return false; + } } + return true; } - return true; - } - case '$containedBy': { - for (const value of object[key]) { - if (!contains(compareTo, value)) { - return false; + case '$containedBy': { + for (const value of object[key]) { + if (!contains(compareTo, value)) { + return false; + } } + return true; } - return true; - } - case '$geoWithin': { - if (compareTo.$polygon) { - const points = compareTo.$polygon.map(geoPoint => [ - geoPoint.latitude, - geoPoint.longitude, - ]); - const polygon = new ParsePolygon(points); - return polygon.containsPoint(object[key]); + case '$geoWithin': { + if (compareTo.$polygon) { + const points = compareTo.$polygon.map(geoPoint => [ + geoPoint.latitude, + geoPoint.longitude, + ]); + const polygon = new ParsePolygon(points); + return polygon.containsPoint(object[key]); + } + if (compareTo.$centerSphere) { + const [WGS84Point, maxDistance] = compareTo.$centerSphere; + const centerPoint = new ParseGeoPoint({ + latitude: WGS84Point[1], + longitude: WGS84Point[0], + }); + const point = new ParseGeoPoint(object[key]); + const distance = point.radiansTo(centerPoint); + return distance <= maxDistance; + } + return false; } - if (compareTo.$centerSphere) { - const [WGS84Point, maxDistance] = compareTo.$centerSphere; - const centerPoint = new ParseGeoPoint({ - latitude: WGS84Point[1], - longitude: WGS84Point[0], - }); - const point = new ParseGeoPoint(object[key]); - const distance = point.radiansTo(centerPoint); - return distance <= maxDistance; + case '$geoIntersects': { + const polygon = new ParsePolygon(object[key].coordinates); + const point = new ParseGeoPoint(compareTo.$point); + return polygon.containsPoint(point); } - return false; - } - case '$geoIntersects': { - const polygon = new ParsePolygon(object[key].coordinates); - const point = new ParseGeoPoint(compareTo.$point); - return polygon.containsPoint(point); - } - default: - return false; + default: + return false; } } return true; } -function validateQuery(query: any) { - let q = query; +function validateQuery(query: Query | QueryJSON) { + let q: Query | QueryJSON | WhereClause = query; - if (query.toJSON) { + if ('toJSON' in query) { q = query.toJSON().where; } const specialQuerykeys = [ diff --git a/src/ParseUser.ts b/src/ParseUser.ts index 684873a5d..b514b4645 100644 --- a/src/ParseUser.ts +++ b/src/ParseUser.ts @@ -14,9 +14,9 @@ import type { RequestOptions, FullOptions } from './RESTController'; export type AuthData = { [key: string]: any }; -type AuthProviderType = { +export type AuthProviderType = { authenticate?(options: { - error?: (provider: AuthProviderType, error: string) => void, + error?: (provider: AuthProviderType, error: string | any) => void, success?: (provider: AuthProviderType, result: AuthData) => void, }): void, From 0334a07911efe9aba5a620c40debc6e263a72230 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 08:24:26 +0700 Subject: [PATCH 17/27] added facebook types --- src/OfflineQuery.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/OfflineQuery.ts b/src/OfflineQuery.ts index 5a1e842ce..674d2ac32 100644 --- a/src/OfflineQuery.ts +++ b/src/OfflineQuery.ts @@ -599,3 +599,4 @@ const OfflineQuery = { }; module.exports = OfflineQuery; +export default OfflineQuery; \ No newline at end of file From d1b2dde69ec3a3bc71e8519558ec3453814a7579 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Mon, 30 Oct 2023 08:34:45 +0700 Subject: [PATCH 18/27] ok but failing tests --- src/FacebookUtils.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/FacebookUtils.ts b/src/FacebookUtils.ts index 4020fe2ae..5b744b794 100644 --- a/src/FacebookUtils.ts +++ b/src/FacebookUtils.ts @@ -4,7 +4,6 @@ /* global FB */ import ParseUser from './ParseUser'; import type { AuthProviderType } from './ParseUser'; -import '@types/facebook-js-sdk' let initialized = false; let requestedPermissions; From 4604451ef829a6db9282a70e78a8575615c8adad Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Tue, 31 Oct 2023 06:15:11 +0700 Subject: [PATCH 19/27] reverted changes to tests, try another approach --- src/LiveQueryClient.ts | 5 +++-- src/Parse.ts | 13 +++++++------ src/ParseFile.ts | 3 +-- src/ParseRole.ts | 3 +-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/LiveQueryClient.ts b/src/LiveQueryClient.ts index 97667b435..1e93b3b8e 100644 --- a/src/LiveQueryClient.ts +++ b/src/LiveQueryClient.ts @@ -192,7 +192,9 @@ class LiveQueryClient { */ subscribe(query: ParseQuery, sessionToken?: string): LiveQuerySubscription { if (!query) { - throw new ParseError(ParseError.INCORRECT_TYPE, 'Subscribe requires a query.') + // Might seem counterintuitive to simply return undefined instead of throwing + // But the tests currently expect this undefined return. + return undefined; } const className = query.className; const queryJSON = query.toJSON(); @@ -522,5 +524,4 @@ if (process.env.PARSE_BUILD === 'node') { } else if (process.env.PARSE_BUILD === 'react-native') { CoreManager.setWebSocketController(WebSocket as any); } - export default LiveQueryClient; diff --git a/src/Parse.ts b/src/Parse.ts index 7863ec793..0085383ff 100644 --- a/src/Parse.ts +++ b/src/Parse.ts @@ -1,10 +1,7 @@ -import decode from './decode'; -import encode from './encode'; import CryptoController from './CryptoController'; import EventuallyQueue from './EventuallyQueue'; import IndexedDBStorageController from './IndexedDBStorageController'; import InstallationController from './InstallationController'; -import * as ParseOp from './ParseOp'; import RESTController from './RESTController'; import ACL from './ParseACL'; import * as Analytics from './Analytics' @@ -21,7 +18,7 @@ import GeoPoint from './ParseGeoPoint' import Polygon from './ParsePolygon' import Installation from './ParseInstallation' import LocalDatastore from './LocalDatastore' -import Object from './ParseObject' +import ParseObject from './ParseObject' import * as Push from './Push' import Query from './ParseQuery' import Relation from './ParseRelation' @@ -32,6 +29,10 @@ import Storage from './Storage' import User from './ParseUser' import LiveQuery from './ParseLiveQuery' import LiveQueryClient from './LiveQueryClient' +// Need to reorder these last due to them requiring ParseObject/ParseRole, etc to be defined first +import * as ParseOp from './ParseOp'; +import decode from './decode'; +import encode from './encode'; /** * Contains all Parse API classes and functions. @@ -63,7 +64,7 @@ interface ParseType { Polygon: typeof Polygon, Installation: typeof Installation, LocalDatastore: typeof LocalDatastore, - Object: typeof Object, + Object: typeof ParseObject, Op: { Set: typeof ParseOp.SetOp, Unset: typeof ParseOp.UnsetOp, @@ -130,7 +131,7 @@ const Parse: ParseType = { Polygon: Polygon, Installation: Installation, LocalDatastore: LocalDatastore, - Object: Object, + Object: ParseObject, Op: { Set: ParseOp.SetOp, Unset: ParseOp.UnsetOp, diff --git a/src/ParseFile.ts b/src/ParseFile.ts index 3904679d9..cd397c8af 100644 --- a/src/ParseFile.ts +++ b/src/ParseFile.ts @@ -34,7 +34,7 @@ export type FileSource = type: string, }; -function b64Digit(number: number): string { +export function b64Digit(number: number): string { if (number < 26) { return String.fromCharCode(65 + number); } @@ -574,4 +574,3 @@ const DefaultController = { CoreManager.setFileController(DefaultController); export default ParseFile; -exports.b64Digit = b64Digit; diff --git a/src/ParseRole.ts b/src/ParseRole.ts index badf6df69..9dbd00315 100644 --- a/src/ParseRole.ts +++ b/src/ParseRole.ts @@ -2,9 +2,9 @@ * @flow */ +import ParseObject from './ParseObject'; import ParseACL from './ParseACL'; import ParseError from './ParseError'; -import ParseObject from './ParseObject'; import type { AttributeMap } from './ObjectStateMutations'; import type ParseRelation from './ParseRelation'; @@ -142,5 +142,4 @@ class ParseRole extends ParseObject { } ParseObject.registerSubclass('_Role', ParseRole); - export default ParseRole; From 606061f7ee17f7705f69cb6ad76e670e628ffb33 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Tue, 31 Oct 2023 06:18:46 +0700 Subject: [PATCH 20/27] slightly better typings and test correction --- src/__tests__/escape-test.js | 2 +- src/promiseUtils.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/__tests__/escape-test.js b/src/__tests__/escape-test.js index 11e6e07af..767d5723a 100644 --- a/src/__tests__/escape-test.js +++ b/src/__tests__/escape-test.js @@ -1,6 +1,6 @@ jest.autoMockOff(); -const escape = require('../escape.js').default; +const escape = require('../escape').default; describe('escape', () => { it('escapes special HTML characters', () => { diff --git a/src/promiseUtils.ts b/src/promiseUtils.ts index aa3d2d153..1302776b2 100644 --- a/src/promiseUtils.ts +++ b/src/promiseUtils.ts @@ -12,13 +12,13 @@ export function resolvingPromise() { return ret; } -export function when(promises: Promise | Promise[]) { +export function when(promises: Promise | (Promise[]), ...others: Promise[]) { let objects: Promise[]; const arrayArgument = Array.isArray(promises); if (arrayArgument) { objects = promises; } else { - objects = [promises]; + objects = arguments as any as Promise[]; } let total = objects.length; From b7a6b27d954ee90598fafd571b9c49afa41e768c Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Tue, 31 Oct 2023 06:33:35 +0700 Subject: [PATCH 21/27] almost all passes now just need those ParseObject definitions loaded before ParseRole --- src/ParseObject.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ParseObject.ts b/src/ParseObject.ts index 2a7f5a3d2..270a0ba9e 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.ts @@ -707,15 +707,15 @@ class ParseObject { * The only supported option is error. * @returns {(ParseObject|boolean)} true if the set succeeded. */ - set(keyOrAttributes: string | AttributeMap, valueOrOptions?: any, options?: any): ParseObject | boolean { - let changes: AttributeMap = {}; + set(key: any, value?: any, options?: any): ParseObject | boolean { + // TODO: Improve types here without breaking stuff. + let changes = {}; const newOps = {}; - let key: string | undefined; - if (keyOrAttributes && typeof keyOrAttributes === 'object') { - changes = keyOrAttributes; - options = valueOrOptions; + if (key && typeof key === 'object') { + changes = key; + options = value; } else if (typeof key === 'string') { - changes[key] = valueOrOptions; + changes[key] = value; } else { // Key is weird; just return ourself return this; From 4273aded1290cf73f44be8a7c94f99823e1b85d9 Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Thu, 2 Nov 2023 06:56:45 +0700 Subject: [PATCH 22/27] fixed more failing tests.. almost there. --- src/CoreManager.ts | 2 +- src/ParseConfig.ts | 2 +- src/ParseQuery.ts | 4 ++-- src/ParseSchema.ts | 3 +-- src/RESTController.ts | 2 +- src/__tests__/Hooks-test.js | 1 + src/__tests__/ParseConfig-test.js | 1 + src/decode.ts | 2 +- 8 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/CoreManager.ts b/src/CoreManager.ts index 661da25e8..dd27568b6 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -25,7 +25,7 @@ type CloudController = { startJob: (name: string, data: any, options: RequestOptions) => Promise, }; type ConfigController = { - current: () => Promise, + current: () => Promise | ParseConfig, get: (opts?: RequestOptions) => Promise, save: (attrs: { [key: string]: any }, masterKeyOnlyFlags?: { [key: string]: any }) => Promise, }; diff --git a/src/ParseConfig.ts b/src/ParseConfig.ts index 89ed810b9..9f18dc7d4 100644 --- a/src/ParseConfig.ts +++ b/src/ParseConfig.ts @@ -139,7 +139,7 @@ function decodePayload(data) { } const DefaultController = { - current: async ()=> { + current: ()=> { if (currentConfig) { return currentConfig; } diff --git a/src/ParseQuery.ts b/src/ParseQuery.ts index 3e6d5edf2..43aa88af2 100644 --- a/src/ParseQuery.ts +++ b/src/ParseQuery.ts @@ -2135,8 +2135,8 @@ class ParseQuery { this._xhrRequest.onchange = () => { }; return this; } - // TODO: Typescript.. How does this work? Does this even make sense? - return (this._xhrRequest.onchange = () => this.cancel()); + this._xhrRequest.onchange = () => this.cancel(); + return this; } _setRequestTask(options) { diff --git a/src/ParseSchema.ts b/src/ParseSchema.ts index de5bca077..b878736c6 100644 --- a/src/ParseSchema.ts +++ b/src/ParseSchema.ts @@ -227,8 +227,7 @@ class ParseSchema { return this.addPointer(name, options.targetClass!, options); } if (type === 'Relation') { - // TODO: Why does options exist here? - return this.addRelation(name, options.targetClass, options); + return this.addRelation(name, options.targetClass); } const fieldOptions: Partial & { type: ValidFieldType, diff --git a/src/RESTController.ts b/src/RESTController.ts index a4bd56d2e..c0ce2649f 100644 --- a/src/RESTController.ts +++ b/src/RESTController.ts @@ -348,4 +348,4 @@ const RESTController = { }; module.exports = RESTController; -export default RESTController; \ No newline at end of file +export default RESTController; diff --git a/src/__tests__/Hooks-test.js b/src/__tests__/Hooks-test.js index 10cd9acde..365070fdd 100644 --- a/src/__tests__/Hooks-test.js +++ b/src/__tests__/Hooks-test.js @@ -3,6 +3,7 @@ jest.dontMock('../CoreManager'); jest.dontMock('../decode'); jest.dontMock('../encode'); jest.dontMock('../ParseError'); +jest.dontMock('../ParseObject'); const Hooks = require('../ParseHooks'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/ParseConfig-test.js b/src/__tests__/ParseConfig-test.js index a3aa5546b..4eeea6da7 100644 --- a/src/__tests__/ParseConfig-test.js +++ b/src/__tests__/ParseConfig-test.js @@ -10,6 +10,7 @@ jest.dontMock('../RESTController'); jest.dontMock('../Storage'); jest.dontMock('../StorageController.default'); jest.dontMock('./test_helpers/mockAsyncStorage'); +jest.dontMock('../ParseObject'); const mockAsyncStorage = require('./test_helpers/mockAsyncStorage'); const CoreManager = require('../CoreManager'); diff --git a/src/decode.ts b/src/decode.ts index 4e4a6cfbe..577e2ddf1 100644 --- a/src/decode.ts +++ b/src/decode.ts @@ -32,7 +32,7 @@ export default function decode(value: any): any { } if (value.__type === 'Relation') { // The parent and key fields will be populated by the parent - const relation = new ParseRelation(undefined, undefined); + const relation = new ParseRelation(null, null); // null, null; since tests expect this. relation.targetClassName = value.className; return relation; } From 5d551477cf20ac4bf524bd0489b2336c4c042ceb Mon Sep 17 00:00:00 2001 From: Switt Kongdachalert Date: Thu, 2 Nov 2023 08:50:56 +0700 Subject: [PATCH 23/27] all tests passing now --- package.json | 1 - src/__tests__/decode-test.js | 10 +++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 205674490..4a30a09b4 100644 --- a/package.json +++ b/package.json @@ -121,7 +121,6 @@ }, "husky": { "hooks": { - "pre-commit": "lint-staged" } }, "lint-staged": { diff --git a/src/__tests__/decode-test.js b/src/__tests__/decode-test.js index 854996e5f..e9e6cc046 100644 --- a/src/__tests__/decode-test.js +++ b/src/__tests__/decode-test.js @@ -2,6 +2,9 @@ jest.dontMock('../decode'); jest.dontMock('../ParseFile'); jest.dontMock('../ParseGeoPoint'); jest.dontMock('../ParsePolygon'); +// Additional unmocks; +jest.dontMock('../ParseObject'); +jest.dontMock('../CoreManager'); const decode = require('../decode').default; @@ -74,7 +77,7 @@ describe('decode', () => { expect(obj.constructor.mock.calls[0]).toEqual([null, null]); expect(obj.targetClassName).toBe('Delivery'); }); - + const spy = jest.spyOn(ParseObject, 'fromJSON'); it('decodes Pointers', () => { const data = { __type: 'Pointer', @@ -82,17 +85,18 @@ describe('decode', () => { objectId: '1001', }; decode(data); - expect(ParseObject.fromJSON.mock.calls[0][0]).toEqual(data); + expect(spy.mock.calls[0][0]).toEqual(data); }); it('decodes ParseObjects', () => { + // const spy = jest.spyOn(ParseObject, 'fromJSON'); const data = { __type: 'Object', className: 'Item', objectId: '1001', }; decode(data); - expect(ParseObject.fromJSON.mock.calls[1][0]).toEqual(data); + expect(spy.mock.calls[1][0]).toEqual(data); }); it('iterates over arrays', () => { From 7fef8b722cc311ca263c442cd5d3ecbf70a27b7b Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Thu, 9 Nov 2023 21:43:47 -0600 Subject: [PATCH 24/27] revert unit tests --- src/__tests__/Hooks-test.js | 1 - src/__tests__/ParseConfig-test.js | 1 - src/__tests__/decode-test.js | 10 +++------- src/{decode.ts => decode.js} | 5 ++--- 4 files changed, 5 insertions(+), 12 deletions(-) rename src/{decode.ts => decode.js} (90%) diff --git a/src/__tests__/Hooks-test.js b/src/__tests__/Hooks-test.js index 365070fdd..10cd9acde 100644 --- a/src/__tests__/Hooks-test.js +++ b/src/__tests__/Hooks-test.js @@ -3,7 +3,6 @@ jest.dontMock('../CoreManager'); jest.dontMock('../decode'); jest.dontMock('../encode'); jest.dontMock('../ParseError'); -jest.dontMock('../ParseObject'); const Hooks = require('../ParseHooks'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/ParseConfig-test.js b/src/__tests__/ParseConfig-test.js index 4eeea6da7..a3aa5546b 100644 --- a/src/__tests__/ParseConfig-test.js +++ b/src/__tests__/ParseConfig-test.js @@ -10,7 +10,6 @@ jest.dontMock('../RESTController'); jest.dontMock('../Storage'); jest.dontMock('../StorageController.default'); jest.dontMock('./test_helpers/mockAsyncStorage'); -jest.dontMock('../ParseObject'); const mockAsyncStorage = require('./test_helpers/mockAsyncStorage'); const CoreManager = require('../CoreManager'); diff --git a/src/__tests__/decode-test.js b/src/__tests__/decode-test.js index e9e6cc046..854996e5f 100644 --- a/src/__tests__/decode-test.js +++ b/src/__tests__/decode-test.js @@ -2,9 +2,6 @@ jest.dontMock('../decode'); jest.dontMock('../ParseFile'); jest.dontMock('../ParseGeoPoint'); jest.dontMock('../ParsePolygon'); -// Additional unmocks; -jest.dontMock('../ParseObject'); -jest.dontMock('../CoreManager'); const decode = require('../decode').default; @@ -77,7 +74,7 @@ describe('decode', () => { expect(obj.constructor.mock.calls[0]).toEqual([null, null]); expect(obj.targetClassName).toBe('Delivery'); }); - const spy = jest.spyOn(ParseObject, 'fromJSON'); + it('decodes Pointers', () => { const data = { __type: 'Pointer', @@ -85,18 +82,17 @@ describe('decode', () => { objectId: '1001', }; decode(data); - expect(spy.mock.calls[0][0]).toEqual(data); + expect(ParseObject.fromJSON.mock.calls[0][0]).toEqual(data); }); it('decodes ParseObjects', () => { - // const spy = jest.spyOn(ParseObject, 'fromJSON'); const data = { __type: 'Object', className: 'Item', objectId: '1001', }; decode(data); - expect(spy.mock.calls[1][0]).toEqual(data); + expect(ParseObject.fromJSON.mock.calls[1][0]).toEqual(data); }); it('iterates over arrays', () => { diff --git a/src/decode.ts b/src/decode.js similarity index 90% rename from src/decode.ts rename to src/decode.js index 577e2ddf1..557002015 100644 --- a/src/decode.ts +++ b/src/decode.js @@ -9,13 +9,12 @@ import ParseObject from './ParseObject'; import { opFromJSON } from './ParseOp'; import ParseRelation from './ParseRelation'; -/** Decodes values from storage type */ export default function decode(value: any): any { if (value === null || typeof value !== 'object' || value instanceof Date) { return value; } if (Array.isArray(value)) { - const dup: any[] = []; + const dup = []; value.forEach((v, i) => { dup[i] = decode(v); }); @@ -32,7 +31,7 @@ export default function decode(value: any): any { } if (value.__type === 'Relation') { // The parent and key fields will be populated by the parent - const relation = new ParseRelation(null, null); // null, null; since tests expect this. + const relation = new ParseRelation(null, null); relation.targetClassName = value.className; return relation; } From 1fb6900b64c1e424aa95b005ac3cec0d5a307cb2 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Thu, 9 Nov 2023 22:04:32 -0600 Subject: [PATCH 25/27] clean up --- package.json | 1 + src/CoreManager.ts | 1 - src/EventEmitter.ts | 2 +- src/IndexedDBStorageController.ts | 2 +- src/InstallationController.ts | 2 +- src/LocalDatastoreController.react-native.ts | 2 +- src/LocalDatastoreController.ts | 2 +- src/OfflineQuery.ts | 2 +- src/{ParseObject.ts => ParseObject.js} | 261 +++++++++---------- src/ParseQuery.ts | 6 +- src/ParseUser.ts | 2 +- src/StorageController.browser.ts | 2 +- src/StorageController.default.ts | 2 +- src/StorageController.react-native.ts | 2 +- src/encode.ts | 2 - 15 files changed, 132 insertions(+), 159 deletions(-) rename src/{ParseObject.ts => ParseObject.js} (91%) diff --git a/package.json b/package.json index c000d0ccf..d5b8b3c33 100644 --- a/package.json +++ b/package.json @@ -121,6 +121,7 @@ }, "husky": { "hooks": { + "pre-commit": "lint-staged" } }, "lint-staged": { diff --git a/src/CoreManager.ts b/src/CoreManager.ts index dd27568b6..9c8325683 100644 --- a/src/CoreManager.ts +++ b/src/CoreManager.ts @@ -230,7 +230,6 @@ type Config = { }; const config: Config & { [key: string]: any } = { - // Defaults IS_NODE: typeof process !== 'undefined' && !!process.versions && diff --git a/src/EventEmitter.ts b/src/EventEmitter.ts index acf63b5f4..205baf4c0 100644 --- a/src/EventEmitter.ts +++ b/src/EventEmitter.ts @@ -22,4 +22,4 @@ try { // EventEmitter unavailable } module.exports = EventEmitter!; -export default EventEmitter!; \ No newline at end of file +export default EventEmitter!; diff --git a/src/IndexedDBStorageController.ts b/src/IndexedDBStorageController.ts index 3dc0e8fc6..cfb6e1c78 100644 --- a/src/IndexedDBStorageController.ts +++ b/src/IndexedDBStorageController.ts @@ -39,4 +39,4 @@ if (typeof window !== 'undefined' && window.indexedDB) { // IndexedDB not supported module.exports = undefined; } -export default IndexedDBStorageController; \ No newline at end of file +export default IndexedDBStorageController; diff --git a/src/InstallationController.ts b/src/InstallationController.ts index 1322a65f3..4a5e027ae 100644 --- a/src/InstallationController.ts +++ b/src/InstallationController.ts @@ -36,4 +36,4 @@ const InstallationController = { }; module.exports = InstallationController; -export default InstallationController; \ No newline at end of file +export default InstallationController; diff --git a/src/LocalDatastoreController.react-native.ts b/src/LocalDatastoreController.react-native.ts index 7add98fbd..1fede2801 100644 --- a/src/LocalDatastoreController.react-native.ts +++ b/src/LocalDatastoreController.react-native.ts @@ -86,4 +86,4 @@ const LocalDatastoreController = { }; module.exports = LocalDatastoreController; -export default LocalDatastoreController; \ No newline at end of file +export default LocalDatastoreController; diff --git a/src/LocalDatastoreController.ts b/src/LocalDatastoreController.ts index 066e15826..f2d050270 100644 --- a/src/LocalDatastoreController.ts +++ b/src/LocalDatastoreController.ts @@ -65,4 +65,4 @@ const LocalDatastoreController = { }; module.exports = LocalDatastoreController; -export default LocalDatastoreController; \ No newline at end of file +export default LocalDatastoreController; diff --git a/src/OfflineQuery.ts b/src/OfflineQuery.ts index 674d2ac32..e0477e16f 100644 --- a/src/OfflineQuery.ts +++ b/src/OfflineQuery.ts @@ -599,4 +599,4 @@ const OfflineQuery = { }; module.exports = OfflineQuery; -export default OfflineQuery; \ No newline at end of file +export default OfflineQuery; diff --git a/src/ParseObject.ts b/src/ParseObject.js similarity index 91% rename from src/ParseObject.ts rename to src/ParseObject.js index 270a0ba9e..32701191b 100644 --- a/src/ParseObject.ts +++ b/src/ParseObject.js @@ -36,13 +36,12 @@ import unsavedChildren from './unsavedChildren'; import type { AttributeMap, OpsMap } from './ObjectStateMutations'; import type { RequestOptions, FullOptions } from './RESTController'; -import uuidv4 from './uuid'; +const uuidv4 = require('./uuid'); export type Pointer = { __type: string, className: string, - objectId?: string, - _localId?: string + objectId: string, }; type SaveParams = { @@ -54,7 +53,6 @@ type SaveParams = { export type SaveOptions = FullOptions & { cascadeSave?: boolean, context?: AttributeMap, - batchSize?: number }; // Mapping of class names to constructors, so we can populate objects from the @@ -82,10 +80,6 @@ function getServerUrlPath() { return url.substr(url.indexOf('/')); } -type ObjectFetchOptions = { - useMasterKey?: boolean, sessionToken?: string, include?: string | string[], context?: AttributeMap, -} - /** * Creates a new model with defined attributes. * @@ -111,8 +105,8 @@ class ParseObject { * @param {object} options The options for this object instance. */ constructor( - className?: string | { className: string, [attr: string]: any }, - attributes?: { [attr: string]: any }, + className: ?string | { className: string, [attr: string]: mixed }, + attributes?: { [attr: string]: mixed }, options?: { ignoreValidation: boolean } ) { // Enable legacy initializers @@ -120,7 +114,7 @@ class ParseObject { this.initialize.apply(this, arguments); } - let toSet: { [attr: string]: any } | null = null; + let toSet = null; this._objCount = objectCount++; if (typeof className === 'string') { this.className = className; @@ -136,7 +130,7 @@ class ParseObject { } } if (attributes && typeof attributes === 'object') { - options = attributes as any; + options = attributes; } } if (toSet && !this.set(toSet, options)) { @@ -149,11 +143,10 @@ class ParseObject { * * @property {string} id */ - id?: string; - _localId?: string; + id: ?string; + _localId: ?string; _objCount: number; className: string; - static className: string; /* Prototype getters / setters */ @@ -168,7 +161,7 @@ class ParseObject { * @property {Date} createdAt * @returns {Date} */ - get createdAt(): Date | undefined { + get createdAt(): ?Date { return this._getServerData().createdAt; } @@ -178,7 +171,7 @@ class ParseObject { * @property {Date} updatedAt * @returns {Date} */ - get updatedAt(): Date | undefined { + get updatedAt(): ?Date { return this._getServerData().updatedAt; } @@ -287,7 +280,7 @@ class ParseObject { } _toFullJSON(seen?: Array, offline?: boolean): AttributeMap { - const json: { [key: string]: any } = this.toJSON(seen, offline); + const json: { [key: string]: mixed } = this.toJSON(seen, offline); json.__type = 'Object'; json.className = this.className; return json; @@ -297,7 +290,7 @@ class ParseObject { const pending = this._getPendingOps(); const dirtyObjects = this._getDirtyObjectAttributes(); const json = {}; - let attr: string; + let attr; for (attr in dirtyObjects) { let isDotNotation = false; @@ -353,12 +346,7 @@ class ParseObject { } const stateController = CoreManager.getObjectStateController(); stateController.initializeState(this._getStateIdentifier()); - const decoded: Partial<{ - createdAt?: Date, - updatedAt?: Date, - ACL?: any // TODO: Maybe type this better? - [key: string]: any - }> = {}; + const decoded = {}; for (const attr in serverData) { if (attr === 'ACL') { decoded[attr] = new ParseACL(serverData[attr]); @@ -370,10 +358,10 @@ class ParseObject { } } if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = parseDate(decoded.createdAt) || undefined; + decoded.createdAt = parseDate(decoded.createdAt); } if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = parseDate(decoded.updatedAt) || undefined; + decoded.updatedAt = parseDate(decoded.updatedAt); } if (!decoded.updatedAt && decoded.createdAt) { decoded.updatedAt = decoded.createdAt; @@ -407,22 +395,16 @@ class ParseObject { } _handleSaveResponse(response: AttributeMap, status: number) { - const changes: Partial<{ - createdAt: string, - updatedAt: string, - [key: string]: any - }> = {}; + const changes = {}; let attr; const stateController = CoreManager.getObjectStateController(); const pending = stateController.popPendingState(this._getStateIdentifier()); - if (pending) { - for (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 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) { @@ -480,7 +462,7 @@ class ParseObject { toJSON(seen: Array | void, offline?: boolean): AttributeMap { const seenEntry = this.id ? this.className + ':' + this.id : this; seen = seen || [seenEntry]; - const json: AttributeMap = {}; + const json = {}; const attrs = this.attributes; for (const attr in attrs) { if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { @@ -506,7 +488,7 @@ class ParseObject { * @param {object} other - An other object ot compare * @returns {boolean} */ - equals(other: any): boolean { + equals(other: mixed): boolean { if (this === other) { return true; } @@ -620,7 +602,7 @@ class ParseObject { * @param {string} attr The string name of an attribute. * @returns {*} */ - get(attr: string): any { + get(attr: string): mixed { return this.attributes[attr]; } @@ -707,8 +689,7 @@ class ParseObject { * The only supported option is error. * @returns {(ParseObject|boolean)} true if the set succeeded. */ - set(key: any, value?: any, options?: any): ParseObject | boolean { - // TODO: Improve types here without breaking stuff. + set(key: mixed, value: mixed, options?: mixed): ParseObject | boolean { let changes = {}; const newOps = {}; if (key && typeof key === 'object') { @@ -717,15 +698,13 @@ class ParseObject { } else if (typeof key === 'string') { changes[key] = value; } else { - // Key is weird; just return ourself return this; } options = options || {}; - /** Readonly attributes of the object class */ - let readonly: string[] = []; - if (typeof ((this.constructor as any).readOnlyAttributes) === 'function') { - readonly = readonly.concat((this.constructor as any).readOnlyAttributes()); + let readonly = []; + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); } for (const k in changes) { if (k === 'createdAt' || k === 'updatedAt') { @@ -808,7 +787,7 @@ class ParseObject { * @param options * @returns {(ParseObject | boolean)} */ - unset(attr: string, options?: { [opt: string]: any }): ParseObject | boolean { + unset(attr: string, options?: { [opt: string]: mixed }): ParseObject | boolean { options = options || {}; options.unset = true; return this.set(attr, null, options); @@ -858,7 +837,7 @@ class ParseObject { * @param item {} The item to add. * @returns {(ParseObject | boolean)} */ - add(attr: string, item: any): ParseObject | boolean { + add(attr: string, item: mixed): ParseObject | boolean { return this.set(attr, new AddOp([item])); } @@ -870,7 +849,7 @@ class ParseObject { * @param items {Object[]} The items to add. * @returns {(ParseObject | boolean)} */ - addAll(attr: string, items: Array): ParseObject | boolean { + addAll(attr: string, items: Array): ParseObject | boolean { return this.set(attr, new AddOp(items)); } @@ -883,7 +862,7 @@ class ParseObject { * @param item {} The object to add. * @returns {(ParseObject | boolean)} */ - addUnique(attr: string, item: any): ParseObject | boolean { + addUnique(attr: string, item: mixed): ParseObject | boolean { return this.set(attr, new AddUniqueOp([item])); } @@ -896,7 +875,7 @@ class ParseObject { * @param items {Object[]} The objects to add. * @returns {(ParseObject | boolean)} */ - addAllUnique(attr: string, items: Array): ParseObject | boolean { + addAllUnique(attr: string, items: Array): ParseObject | boolean { return this.set(attr, new AddUniqueOp(items)); } @@ -908,7 +887,7 @@ class ParseObject { * @param item {} The object to remove. * @returns {(ParseObject | boolean)} */ - remove(attr: string, item: any): ParseObject | boolean { + remove(attr: string, item: mixed): ParseObject | boolean { return this.set(attr, new RemoveOp([item])); } @@ -920,7 +899,7 @@ class ParseObject { * @param items {Object[]} The object to remove. * @returns {(ParseObject | boolean)} */ - removeAll(attr: string, items: Array): ParseObject | boolean { + removeAll(attr: string, items: Array): ParseObject | boolean { return this.set(attr, new RemoveOp(items)); } @@ -933,7 +912,7 @@ class ParseObject { * @param attr {String} The key. * @returns {Parse.Op | undefined} The operation, or undefined if none. */ - op(attr: string): Op | undefined { + op(attr: string): ?Op { const pending = this._getPendingOps(); for (let i = pending.length; i--;) { if (pending[i][attr]) { @@ -947,11 +926,11 @@ class ParseObject { * * @returns {Parse.Object} */ - clone(): typeof this { - const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className); + clone(): any { + const clone = new this.constructor(this.className); let attributes = this.attributes; - if (typeof (this.constructor as any).readOnlyAttributes === 'function') { - const readonly = (this.constructor as any).readOnlyAttributes() || []; + if (typeof this.constructor.readOnlyAttributes === 'function') { + const readonly = this.constructor.readOnlyAttributes() || []; // Attributes are frozen, so we have to rebuild an object, // rather than delete readonly keys const copy = {}; @@ -974,7 +953,7 @@ class ParseObject { * @returns {Parse.Object} */ newInstance(): any { - const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className); + const clone = new this.constructor(this.className); clone.id = this.id; if (singleInstance) { // Just return an object with the right id @@ -1081,7 +1060,7 @@ class ParseObject { * @returns {Parse.ACL|null} An instance of Parse.ACL. * @see Parse.Object#get */ - getACL(): ParseACL | null { + getACL(): ?ParseACL { const acl = this.get('ACL'); if (acl instanceof ParseACL) { return acl; @@ -1097,7 +1076,7 @@ class ParseObject { * @returns {(ParseObject | boolean)} Whether the set passed validation. * @see Parse.Object#set */ - setACL(acl: ParseACL, options?: any): ParseObject | boolean { + setACL(acl: ParseACL, options?: mixed): ParseObject | boolean { return this.set('ACL', acl, options); } @@ -1130,8 +1109,8 @@ class ParseObject { const attributes = this.attributes; const erasable = {}; let readonly = ['createdAt', 'updatedAt']; - if (typeof (this.constructor as any).readOnlyAttributes === 'function') { - readonly = readonly.concat((this.constructor as any).readOnlyAttributes()); + if (typeof this.constructor.readOnlyAttributes === 'function') { + readonly = readonly.concat(this.constructor.readOnlyAttributes()); } for (const attr in attributes) { if (readonly.indexOf(attr) < 0) { @@ -1158,9 +1137,9 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the fetch * completes. */ - fetch(options: ObjectFetchOptions): Promise { + fetch(options: RequestOptions): Promise { options = options || {}; - const fetchOptions: ObjectFetchOptions = {}; + const fetchOptions = {}; if (options.hasOwnProperty('useMasterKey')) { fetchOptions.useMasterKey = options.useMasterKey; } @@ -1175,13 +1154,13 @@ class ParseObject { if (Array.isArray(options.include)) { options.include.forEach(key => { if (Array.isArray(key)) { - fetchOptions.include = fetchOptions.include!.concat(key); + fetchOptions.include = fetchOptions.include.concat(key); } else { - (fetchOptions.include as string[]).push(key); + fetchOptions.include.push(key); } }); } else { - fetchOptions.include.push(options.include!); // already checked hasOwnProperty('include') + fetchOptions.include.push(options.include); } } const controller = CoreManager.getObjectController(); @@ -1206,7 +1185,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the fetch * completes. */ - fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise { + fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise { options = options || {}; options.include = keys; return this.fetch(options); @@ -1236,7 +1215,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the save * completes. */ - async saveEventually(options: SaveOptions): Promise { + async saveEventually(options: SaveOptions): Promise { try { await this.save(null, options); } catch (e) { @@ -1312,14 +1291,14 @@ class ParseObject { * completes. */ save( - arg1: undefined | string | { [attr: string]: any } | null, - arg2: SaveOptions | any, + arg1: ?string | { [attr: string]: mixed }, + arg2: SaveOptions | mixed, arg3?: SaveOptions - ): Promise { - let attrs: { [attr: string]: any } | null; - let options: SaveOptions | undefined; - if (typeof arg1 === 'object' || typeof arg1 === 'undefined' || arg1 == null) { - attrs = (arg1 as { [attr: string]: any }) || null; + ): Promise { + let attrs; + let options; + if (typeof arg1 === 'object' || typeof arg1 === 'undefined') { + attrs = arg1; if (typeof arg2 === 'object') { options = arg2; } @@ -1338,7 +1317,7 @@ class ParseObject { } options = options || {}; - const saveOptions: SaveOptions = {}; + const saveOptions = {}; if (options.hasOwnProperty('useMasterKey')) { saveOptions.useMasterKey = !!options.useMasterKey; } @@ -1355,7 +1334,7 @@ class ParseObject { const unsaved = options.cascadeSave !== false ? unsavedChildren(this) : null; return controller.save(unsaved, saveOptions).then(() => { return controller.save(this, saveOptions); - }) as Promise as Promise; + }); } /** @@ -1380,7 +1359,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - async destroyEventually(options: RequestOptions): Promise { + async destroyEventually(options: RequestOptions): Promise { try { await this.destroy(options); } catch (e) { @@ -1406,9 +1385,9 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - destroy(options: RequestOptions): Promise { + destroy(options: RequestOptions): Promise { options = options || {}; - const destroyOptions: RequestOptions = {}; + const destroyOptions = {}; if (options.hasOwnProperty('useMasterKey')) { destroyOptions.useMasterKey = options.useMasterKey; } @@ -1421,7 +1400,7 @@ class ParseObject { if (!this.id) { return Promise.resolve(); } - return CoreManager.getObjectController().destroy(this, destroyOptions) as Promise; + return CoreManager.getObjectController().destroy(this, destroyOptions); } /** @@ -1573,7 +1552,7 @@ class ParseObject { * @returns {Parse.Object[]} */ static fetchAll(list: Array, options: RequestOptions = {}) { - const queryOptions: RequestOptions = {}; + const queryOptions = {}; if (options.hasOwnProperty('useMasterKey')) { queryOptions.useMasterKey = options.useMasterKey; } @@ -1683,8 +1662,10 @@ class ParseObject { * @static * @returns {Parse.Object[]} */ - static fetchAllIfNeeded(list: Array, options: ObjectFetchOptions = {}) { - const queryOptions: ObjectFetchOptions = {}; + static fetchAllIfNeeded(list: Array, options) { + options = options || {}; + + const queryOptions = {}; if (options.hasOwnProperty('useMasterKey')) { queryOptions.useMasterKey = options.useMasterKey; } @@ -1697,8 +1678,8 @@ class ParseObject { return CoreManager.getObjectController().fetch(list, false, queryOptions); } - static handleIncludeOptions(options: { include?: string | string[] }) { - let include: string[] = []; + static handleIncludeOptions(options) { + let include = []; if (Array.isArray(options.include)) { options.include.forEach(key => { if (Array.isArray(key)) { @@ -1708,7 +1689,7 @@ class ParseObject { } }); } else { - include.push(options.include!); + include.push(options.include); } return include; } @@ -1759,8 +1740,8 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroyAll * completes. */ - static destroyAll(list: Array, options: SaveOptions = {}) { - const destroyOptions: SaveOptions = {}; + static destroyAll(list: Array, options = {}) { + const destroyOptions = {}; if (options.hasOwnProperty('useMasterKey')) { destroyOptions.useMasterKey = options.useMasterKey; } @@ -1794,8 +1775,8 @@ class ParseObject { * @static * @returns {Parse.Object[]} */ - static saveAll(list: Array, options: SaveOptions = {}) { - const saveOptions: SaveOptions = {}; + static saveAll(list: Array, options: RequestOptions = {}) { + const saveOptions = {}; if (options.hasOwnProperty('useMasterKey')) { saveOptions.useMasterKey = options.useMasterKey; } @@ -1825,7 +1806,7 @@ class ParseObject { * @static * @returns {Parse.Object} A Parse.Object reference. */ - static createWithoutData(id: string): ParseObject { + static createWithoutData(id: string) { const obj = new this(); obj.id = id; return obj; @@ -1841,13 +1822,13 @@ class ParseObject { * @static * @returns {Parse.Object} A Parse.Object reference */ - static fromJSON(json: any, override?: boolean, dirty?: boolean): ParseObject { + static fromJSON(json: any, override?: boolean, dirty?: boolean) { if (!json.className) { throw new Error('Cannot create an object without a className'); } const constructor = classMap[json.className]; const o = constructor ? new constructor(json.className) : new ParseObject(json.className); - const otherAttributes: AttributeMap = {}; + const otherAttributes = {}; for (const attr in json) { if (attr !== 'className' && attr !== '__type') { otherAttributes[attr] = json[attr]; @@ -1896,7 +1877,7 @@ class ParseObject { if (typeof constructor !== 'function') { throw new TypeError( 'You must register the subclass constructor. ' + - 'Did you attempt to register an instance of the subclass?' + 'Did you attempt to register an instance of the subclass?' ); } classMap[className] = constructor; @@ -1954,7 +1935,7 @@ class ParseObject { * this method. * @returns {Parse.Object} A new subclass of Parse.Object. */ - static extend(className: any, protoProps?: any, classProps?: any) { + static extend(className: any, protoProps: any, classProps: any) { if (typeof className !== 'string') { if (className && typeof className.className === 'string') { return ParseObject.extend(className.className, className, protoProps); @@ -1969,7 +1950,7 @@ class ParseObject { } let parentProto = ParseObject.prototype; - if (this.hasOwnProperty('__super__') && (this as any).__super__) { + if (this.hasOwnProperty('__super__') && this.__super__) { parentProto = this.prototype; } let ParseObjectSubclass = function (attributes, options) { @@ -1995,16 +1976,15 @@ class ParseObject { if (classMap[adjustedClassName]) { ParseObjectSubclass = classMap[adjustedClassName]; } else { - // TODO: Maybe there is a more elegant solution to this? - (ParseObjectSubclass as any).extend = function (name: string, protoProps: any, classProps: any) { + 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 as any).createWithoutData = ParseObject.createWithoutData; - (ParseObjectSubclass as any).className = adjustedClassName; - (ParseObjectSubclass as any).__super__ = parentProto; + ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; + ParseObjectSubclass.className = adjustedClassName; + ParseObjectSubclass.__super__ = parentProto; ParseObjectSubclass.prototype = Object.create(parentProto, { constructor: { value: ParseObjectSubclass, @@ -2215,19 +2195,17 @@ const DefaultController = { target: ParseObject | Array, forceFetch: boolean, options: RequestOptions - ): Promise | ParseObject | undefined> { + ): Promise | ParseObject> { const localDatastore = CoreManager.getLocalDatastore(); if (Array.isArray(target)) { if (target.length < 1) { return Promise.resolve([]); } - /** Resulting Parse.Objects that have data */ - const objs: ParseObject[] = []; - /** IDs to fetch */ - const ids: string[] = []; - let className: null | string = null; - const results: ParseObject[] = []; - let error: ParseError | null = null; + const objs = []; + const ids = []; + let className = null; + const results = []; + let error = null; target.forEach(el => { if (error) { return; @@ -2245,7 +2223,7 @@ const DefaultController = { error = new ParseError(ParseError.MISSING_OBJECT_ID, 'All objects must have an ID'); } if (forceFetch || !el.isDataAvailable()) { - ids.push(el.id!); // Already checked e.id above. + ids.push(el.id); objs.push(el); } results.push(el); @@ -2253,17 +2231,16 @@ const DefaultController = { if (error) { return Promise.reject(error); } - // Construct a ParseQuery that finds objects with matching IDs - const query = new ParseQuery(className!); + const query = new ParseQuery(className); query.containedIn('objectId', ids); if (options && options.include) { query.include(options.include); } query._limit = ids.length; - return query.find(options).then(async (objects: ParseObject[]) => { - const idMap: Record = {}; + return query.find(options).then(async objects => { + const idMap = {}; objects.forEach(o => { - idMap[o.id!] = o; + idMap[o.id] = o; }); for (let i = 0; i < objs.length; i++) { const obj = objs[i]; @@ -2276,7 +2253,7 @@ const DefaultController = { } } if (!singleInstance) { - // If single instance objects are disabled, we need to replace the objects in the results array. + // If single instance objects are disabled, we need to replace the for (let i = 0; i < results.length; i++) { const obj = results[i]; if (obj && obj.id && idMap[obj.id]) { @@ -2298,7 +2275,7 @@ const DefaultController = { ); } const RESTController = CoreManager.getRESTController(); - const params: RequestOptions = {}; + const params = {}; if (options && options.include) { params.include = options.include.join(); } @@ -2315,14 +2292,13 @@ const DefaultController = { return target; }); } - // Not Array, and not ParseObject; return undefined/void. - return Promise.resolve(undefined); + return Promise.resolve(); }, async destroy( target: ParseObject | Array, - options: SaveOptions - ): Promise | ParseObject> { + options: RequestOptions + ): Promise | ParseObject> { const batchSize = options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE'); const localDatastore = CoreManager.getLocalDatastore(); @@ -2332,7 +2308,7 @@ const DefaultController = { if (target.length < 1) { return Promise.resolve([]); } - const batches: ParseObject[][] = [[]]; + const batches = [[]]; target.forEach(obj => { if (!obj.id) { return; @@ -2347,7 +2323,7 @@ const DefaultController = { batches.pop(); } let deleteCompleted = Promise.resolve(); - const errors: ParseError[] = []; + const errors = []; batches.forEach(batch => { deleteCompleted = deleteCompleted.then(() => { return RESTController.request( @@ -2399,7 +2375,7 @@ const DefaultController = { return Promise.resolve(target); }, - save(target: ParseObject | Array | null, options: RequestOptions) { + save(target: ParseObject | Array, options: RequestOptions) { const batchSize = options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE'); const localDatastore = CoreManager.getLocalDatastore(); @@ -2418,14 +2394,13 @@ const DefaultController = { let unsaved = target.concat(); for (let i = 0; i < target.length; i++) { - const target_i = target[i]; - if (target_i instanceof ParseObject) { - unsaved = unsaved.concat(unsavedChildren(target_i, true)); + if (target[i] instanceof ParseObject) { + unsaved = unsaved.concat(unsavedChildren(target[i], true)); } } unsaved = unique(unsaved); - const filesSaved: Array | undefined> = []; + const filesSaved: Array = []; let pending: Array = []; unsaved.forEach(el => { if (el instanceof ParseFile) { @@ -2436,14 +2411,14 @@ const DefaultController = { }); return Promise.all(filesSaved).then(() => { - let objectError: null | ParseError = null; + let objectError = null; return continueWhile( () => { return pending.length > 0; }, () => { - const batch: ParseObject[] = []; - const nextPending: ParseObject[] = []; + const batch = []; + const nextPending = []; pending.forEach(el => { if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(el, 'id') && !el.id) { throw new ParseError( @@ -2467,11 +2442,11 @@ const DefaultController = { // Queue up tasks for each object in the batch. // When every task is ready, the API request will execute - const batchReturned = resolvingPromise(); - const batchReady: ReturnType>[] = []; - const batchTasks: Promise[] = []; + const batchReturned = new resolvingPromise(); + const batchReady = []; + const batchTasks = []; batch.forEach((obj, index) => { - const ready = resolvingPromise(); + const ready = new resolvingPromise(); batchReady.push(ready); const task = function () { ready.resolve(); @@ -2528,7 +2503,7 @@ const DefaultController = { for (const object of target) { // Make sure that it is a ParseObject before updating it into the localDataStore if (object instanceof ParseObject) { - await localDatastore._updateLocalIdForObject(mapIdForPin[object.id!], object); + await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); await localDatastore._updateObjectIfPinned(object); } } diff --git a/src/ParseQuery.ts b/src/ParseQuery.ts index 43aa88af2..70a8d9adb 100644 --- a/src/ParseQuery.ts +++ b/src/ParseQuery.ts @@ -2035,7 +2035,7 @@ class ParseQuery { */ static or(...queries: Array): ParseQuery { const className = _getClassNameFromQueries(queries); - const query = new ParseQuery(className!); // Cast to !; Checked inside ParseQuery constructor anyway + const query = new ParseQuery(className!); query._orQuery(queries); return query; } @@ -2054,7 +2054,7 @@ class ParseQuery { */ static and(...queries: Array): ParseQuery { const className = _getClassNameFromQueries(queries); - const query = new ParseQuery(className!); // Cast to !; Checked inside ParseQuery constructor anyway + const query = new ParseQuery(className!); query._andQuery(queries); return query; } @@ -2073,7 +2073,7 @@ class ParseQuery { */ static nor(...queries: Array): ParseQuery { const className = _getClassNameFromQueries(queries); - const query = new ParseQuery(className!); // Cast to !; Checked inside ParseQuery constructor anyway + const query = new ParseQuery(className!); query._norQuery(queries); return query; } diff --git a/src/ParseUser.ts b/src/ParseUser.ts index b514b4645..1bd4bf1af 100644 --- a/src/ParseUser.ts +++ b/src/ParseUser.ts @@ -512,7 +512,7 @@ class ParseUser extends ParseObject { * the current user when it is destroyed * * @param {...any} args - * @returns {Parse.User|void} seems to depend on implementation (default = void). + * @returns {Parse.User|void} */ async destroy(...args: Array): Promise { await super.destroy.apply(this, args); diff --git a/src/StorageController.browser.ts b/src/StorageController.browser.ts index 9a65ec298..275d63715 100644 --- a/src/StorageController.browser.ts +++ b/src/StorageController.browser.ts @@ -38,4 +38,4 @@ const StorageController = { }; module.exports = StorageController; -export default StorageController; \ No newline at end of file +export default StorageController; diff --git a/src/StorageController.default.ts b/src/StorageController.default.ts index eda3f0d45..c6ab92ceb 100644 --- a/src/StorageController.default.ts +++ b/src/StorageController.default.ts @@ -37,4 +37,4 @@ const StorageController = { }; module.exports = StorageController; -export default StorageController; \ No newline at end of file +export default StorageController; diff --git a/src/StorageController.react-native.ts b/src/StorageController.react-native.ts index 77a3ae069..f44b72bbb 100644 --- a/src/StorageController.react-native.ts +++ b/src/StorageController.react-native.ts @@ -85,4 +85,4 @@ const StorageController = { }; module.exports = StorageController; -export default StorageController; \ No newline at end of file +export default StorageController; diff --git a/src/encode.ts b/src/encode.ts index 86148e8a4..140d54aa5 100644 --- a/src/encode.ts +++ b/src/encode.ts @@ -10,7 +10,6 @@ import ParseObject from './ParseObject'; import { Op } from './ParseOp'; import ParseRelation from './ParseRelation'; -/** Encodes values to storage type */ function encode( value: any, disallowObjects: boolean, @@ -83,7 +82,6 @@ function encode( return value; } -/** Encodes values to storage type */ export default function ( value: any, disallowObjects?: boolean, From 823935dfe3f2d5099853b1da9994205d9d46ee17 Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Thu, 9 Nov 2023 22:41:46 -0600 Subject: [PATCH 26/27] pin package --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index eb8d014a7..29df00318 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,7 @@ "@semantic-release/github": "8.0.7", "@semantic-release/npm": "9.0.2", "@semantic-release/release-notes-generator": "10.0.3", - "@types/facebook-js-sdk": "^3.3.9", + "@types/facebook-js-sdk": "3.3.9", "babel-jest": "29.5.0", "babel-plugin-inline-package-json": "2.0.0", "babel-plugin-minify-dead-code-elimination": "0.5.2", diff --git a/package.json b/package.json index d5b8b3c33..12654f893 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "@semantic-release/github": "8.0.7", "@semantic-release/npm": "9.0.2", "@semantic-release/release-notes-generator": "10.0.3", - "@types/facebook-js-sdk": "^3.3.9", + "@types/facebook-js-sdk": "3.3.9", "babel-jest": "29.5.0", "babel-plugin-inline-package-json": "2.0.0", "babel-plugin-minify-dead-code-elimination": "0.5.2", From 3b8e4dd89704484730f7fbc586b3acc3bdcc9b1b Mon Sep 17 00:00:00 2001 From: Diamond Lewis Date: Fri, 10 Nov 2023 00:30:21 -0600 Subject: [PATCH 27/27] convert all files to ts --- src/{CloudCode.js => CloudCode.ts} | 0 src/{ParseObject.js => ParseObject.ts} | 261 ++++++++++-------- src/{Socket.weapp.js => Socket.weapp.ts} | 17 +- ...er.weapp.js => StorageController.weapp.ts} | 7 +- src/{Xhr.weapp.js => Xhr.weapp.ts} | 23 ++ src/{decode.js => decode.ts} | 6 +- 6 files changed, 191 insertions(+), 123 deletions(-) rename src/{CloudCode.js => CloudCode.ts} (100%) rename src/{ParseObject.js => ParseObject.ts} (91%) rename src/{Socket.weapp.js => Socket.weapp.ts} (64%) rename src/{StorageController.weapp.js => StorageController.weapp.ts} (78%) rename src/{Xhr.weapp.js => Xhr.weapp.ts} (81%) rename src/{decode.js => decode.ts} (90%) diff --git a/src/CloudCode.js b/src/CloudCode.ts similarity index 100% rename from src/CloudCode.js rename to src/CloudCode.ts diff --git a/src/ParseObject.js b/src/ParseObject.ts similarity index 91% rename from src/ParseObject.js rename to src/ParseObject.ts index 32701191b..270a0ba9e 100644 --- a/src/ParseObject.js +++ b/src/ParseObject.ts @@ -36,12 +36,13 @@ import unsavedChildren from './unsavedChildren'; import type { AttributeMap, OpsMap } from './ObjectStateMutations'; import type { RequestOptions, FullOptions } from './RESTController'; -const uuidv4 = require('./uuid'); +import uuidv4 from './uuid'; export type Pointer = { __type: string, className: string, - objectId: string, + objectId?: string, + _localId?: string }; type SaveParams = { @@ -53,6 +54,7 @@ type SaveParams = { export type SaveOptions = FullOptions & { cascadeSave?: boolean, context?: AttributeMap, + batchSize?: number }; // Mapping of class names to constructors, so we can populate objects from the @@ -80,6 +82,10 @@ function getServerUrlPath() { return url.substr(url.indexOf('/')); } +type ObjectFetchOptions = { + useMasterKey?: boolean, sessionToken?: string, include?: string | string[], context?: AttributeMap, +} + /** * Creates a new model with defined attributes. * @@ -105,8 +111,8 @@ class ParseObject { * @param {object} options The options for this object instance. */ constructor( - className: ?string | { className: string, [attr: string]: mixed }, - attributes?: { [attr: string]: mixed }, + className?: string | { className: string, [attr: string]: any }, + attributes?: { [attr: string]: any }, options?: { ignoreValidation: boolean } ) { // Enable legacy initializers @@ -114,7 +120,7 @@ class ParseObject { this.initialize.apply(this, arguments); } - let toSet = null; + let toSet: { [attr: string]: any } | null = null; this._objCount = objectCount++; if (typeof className === 'string') { this.className = className; @@ -130,7 +136,7 @@ class ParseObject { } } if (attributes && typeof attributes === 'object') { - options = attributes; + options = attributes as any; } } if (toSet && !this.set(toSet, options)) { @@ -143,10 +149,11 @@ class ParseObject { * * @property {string} id */ - id: ?string; - _localId: ?string; + id?: string; + _localId?: string; _objCount: number; className: string; + static className: string; /* Prototype getters / setters */ @@ -161,7 +168,7 @@ class ParseObject { * @property {Date} createdAt * @returns {Date} */ - get createdAt(): ?Date { + get createdAt(): Date | undefined { return this._getServerData().createdAt; } @@ -171,7 +178,7 @@ class ParseObject { * @property {Date} updatedAt * @returns {Date} */ - get updatedAt(): ?Date { + get updatedAt(): Date | undefined { return this._getServerData().updatedAt; } @@ -280,7 +287,7 @@ class ParseObject { } _toFullJSON(seen?: Array, offline?: boolean): AttributeMap { - const json: { [key: string]: mixed } = this.toJSON(seen, offline); + const json: { [key: string]: any } = this.toJSON(seen, offline); json.__type = 'Object'; json.className = this.className; return json; @@ -290,7 +297,7 @@ class ParseObject { const pending = this._getPendingOps(); const dirtyObjects = this._getDirtyObjectAttributes(); const json = {}; - let attr; + let attr: string; for (attr in dirtyObjects) { let isDotNotation = false; @@ -346,7 +353,12 @@ class ParseObject { } const stateController = CoreManager.getObjectStateController(); stateController.initializeState(this._getStateIdentifier()); - const decoded = {}; + const decoded: Partial<{ + createdAt?: Date, + updatedAt?: Date, + ACL?: any // TODO: Maybe type this better? + [key: string]: any + }> = {}; for (const attr in serverData) { if (attr === 'ACL') { decoded[attr] = new ParseACL(serverData[attr]); @@ -358,10 +370,10 @@ class ParseObject { } } if (decoded.createdAt && typeof decoded.createdAt === 'string') { - decoded.createdAt = parseDate(decoded.createdAt); + decoded.createdAt = parseDate(decoded.createdAt) || undefined; } if (decoded.updatedAt && typeof decoded.updatedAt === 'string') { - decoded.updatedAt = parseDate(decoded.updatedAt); + decoded.updatedAt = parseDate(decoded.updatedAt) || undefined; } if (!decoded.updatedAt && decoded.createdAt) { decoded.updatedAt = decoded.createdAt; @@ -395,16 +407,22 @@ class ParseObject { } _handleSaveResponse(response: AttributeMap, status: number) { - const changes = {}; + const changes: Partial<{ + createdAt: string, + updatedAt: string, + [key: string]: any + }> = {}; let attr; const stateController = CoreManager.getObjectStateController(); const pending = stateController.popPendingState(this._getStateIdentifier()); - for (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); + if (pending) { + for (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) { @@ -462,7 +480,7 @@ class ParseObject { toJSON(seen: Array | void, offline?: boolean): AttributeMap { const seenEntry = this.id ? this.className + ':' + this.id : this; seen = seen || [seenEntry]; - const json = {}; + const json: AttributeMap = {}; const attrs = this.attributes; for (const attr in attrs) { if ((attr === 'createdAt' || attr === 'updatedAt') && attrs[attr].toJSON) { @@ -488,7 +506,7 @@ class ParseObject { * @param {object} other - An other object ot compare * @returns {boolean} */ - equals(other: mixed): boolean { + equals(other: any): boolean { if (this === other) { return true; } @@ -602,7 +620,7 @@ class ParseObject { * @param {string} attr The string name of an attribute. * @returns {*} */ - get(attr: string): mixed { + get(attr: string): any { return this.attributes[attr]; } @@ -689,7 +707,8 @@ class ParseObject { * The only supported option is error. * @returns {(ParseObject|boolean)} true if the set succeeded. */ - set(key: mixed, value: mixed, options?: mixed): ParseObject | boolean { + set(key: any, value?: any, options?: any): ParseObject | boolean { + // TODO: Improve types here without breaking stuff. let changes = {}; const newOps = {}; if (key && typeof key === 'object') { @@ -698,13 +717,15 @@ class ParseObject { } else if (typeof key === 'string') { changes[key] = value; } else { + // Key is weird; just return ourself return this; } options = options || {}; - let readonly = []; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); + /** Readonly attributes of the object class */ + let readonly: string[] = []; + if (typeof ((this.constructor as any).readOnlyAttributes) === 'function') { + readonly = readonly.concat((this.constructor as any).readOnlyAttributes()); } for (const k in changes) { if (k === 'createdAt' || k === 'updatedAt') { @@ -787,7 +808,7 @@ class ParseObject { * @param options * @returns {(ParseObject | boolean)} */ - unset(attr: string, options?: { [opt: string]: mixed }): ParseObject | boolean { + unset(attr: string, options?: { [opt: string]: any }): ParseObject | boolean { options = options || {}; options.unset = true; return this.set(attr, null, options); @@ -837,7 +858,7 @@ class ParseObject { * @param item {} The item to add. * @returns {(ParseObject | boolean)} */ - add(attr: string, item: mixed): ParseObject | boolean { + add(attr: string, item: any): ParseObject | boolean { return this.set(attr, new AddOp([item])); } @@ -849,7 +870,7 @@ class ParseObject { * @param items {Object[]} The items to add. * @returns {(ParseObject | boolean)} */ - addAll(attr: string, items: Array): ParseObject | boolean { + addAll(attr: string, items: Array): ParseObject | boolean { return this.set(attr, new AddOp(items)); } @@ -862,7 +883,7 @@ class ParseObject { * @param item {} The object to add. * @returns {(ParseObject | boolean)} */ - addUnique(attr: string, item: mixed): ParseObject | boolean { + addUnique(attr: string, item: any): ParseObject | boolean { return this.set(attr, new AddUniqueOp([item])); } @@ -875,7 +896,7 @@ class ParseObject { * @param items {Object[]} The objects to add. * @returns {(ParseObject | boolean)} */ - addAllUnique(attr: string, items: Array): ParseObject | boolean { + addAllUnique(attr: string, items: Array): ParseObject | boolean { return this.set(attr, new AddUniqueOp(items)); } @@ -887,7 +908,7 @@ class ParseObject { * @param item {} The object to remove. * @returns {(ParseObject | boolean)} */ - remove(attr: string, item: mixed): ParseObject | boolean { + remove(attr: string, item: any): ParseObject | boolean { return this.set(attr, new RemoveOp([item])); } @@ -899,7 +920,7 @@ class ParseObject { * @param items {Object[]} The object to remove. * @returns {(ParseObject | boolean)} */ - removeAll(attr: string, items: Array): ParseObject | boolean { + removeAll(attr: string, items: Array): ParseObject | boolean { return this.set(attr, new RemoveOp(items)); } @@ -912,7 +933,7 @@ class ParseObject { * @param attr {String} The key. * @returns {Parse.Op | undefined} The operation, or undefined if none. */ - op(attr: string): ?Op { + op(attr: string): Op | undefined { const pending = this._getPendingOps(); for (let i = pending.length; i--;) { if (pending[i][attr]) { @@ -926,11 +947,11 @@ class ParseObject { * * @returns {Parse.Object} */ - clone(): any { - const clone = new this.constructor(this.className); + clone(): typeof this { + const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className); let attributes = this.attributes; - if (typeof this.constructor.readOnlyAttributes === 'function') { - const readonly = this.constructor.readOnlyAttributes() || []; + if (typeof (this.constructor as any).readOnlyAttributes === 'function') { + const readonly = (this.constructor as any).readOnlyAttributes() || []; // Attributes are frozen, so we have to rebuild an object, // rather than delete readonly keys const copy = {}; @@ -953,7 +974,7 @@ class ParseObject { * @returns {Parse.Object} */ newInstance(): any { - const clone = new this.constructor(this.className); + const clone = new (this.constructor as new (...args: ConstructorParameters) => this)(this.className); clone.id = this.id; if (singleInstance) { // Just return an object with the right id @@ -1060,7 +1081,7 @@ class ParseObject { * @returns {Parse.ACL|null} An instance of Parse.ACL. * @see Parse.Object#get */ - getACL(): ?ParseACL { + getACL(): ParseACL | null { const acl = this.get('ACL'); if (acl instanceof ParseACL) { return acl; @@ -1076,7 +1097,7 @@ class ParseObject { * @returns {(ParseObject | boolean)} Whether the set passed validation. * @see Parse.Object#set */ - setACL(acl: ParseACL, options?: mixed): ParseObject | boolean { + setACL(acl: ParseACL, options?: any): ParseObject | boolean { return this.set('ACL', acl, options); } @@ -1109,8 +1130,8 @@ class ParseObject { const attributes = this.attributes; const erasable = {}; let readonly = ['createdAt', 'updatedAt']; - if (typeof this.constructor.readOnlyAttributes === 'function') { - readonly = readonly.concat(this.constructor.readOnlyAttributes()); + if (typeof (this.constructor as any).readOnlyAttributes === 'function') { + readonly = readonly.concat((this.constructor as any).readOnlyAttributes()); } for (const attr in attributes) { if (readonly.indexOf(attr) < 0) { @@ -1137,9 +1158,9 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the fetch * completes. */ - fetch(options: RequestOptions): Promise { + fetch(options: ObjectFetchOptions): Promise { options = options || {}; - const fetchOptions = {}; + const fetchOptions: ObjectFetchOptions = {}; if (options.hasOwnProperty('useMasterKey')) { fetchOptions.useMasterKey = options.useMasterKey; } @@ -1154,13 +1175,13 @@ class ParseObject { if (Array.isArray(options.include)) { options.include.forEach(key => { if (Array.isArray(key)) { - fetchOptions.include = fetchOptions.include.concat(key); + fetchOptions.include = fetchOptions.include!.concat(key); } else { - fetchOptions.include.push(key); + (fetchOptions.include as string[]).push(key); } }); } else { - fetchOptions.include.push(options.include); + fetchOptions.include.push(options.include!); // already checked hasOwnProperty('include') } } const controller = CoreManager.getObjectController(); @@ -1185,7 +1206,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the fetch * completes. */ - fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise { + fetchWithInclude(keys: String | Array>, options: RequestOptions): Promise { options = options || {}; options.include = keys; return this.fetch(options); @@ -1215,7 +1236,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the save * completes. */ - async saveEventually(options: SaveOptions): Promise { + async saveEventually(options: SaveOptions): Promise { try { await this.save(null, options); } catch (e) { @@ -1291,14 +1312,14 @@ class ParseObject { * completes. */ save( - arg1: ?string | { [attr: string]: mixed }, - arg2: SaveOptions | mixed, + arg1: undefined | string | { [attr: string]: any } | null, + arg2: SaveOptions | any, arg3?: SaveOptions - ): Promise { - let attrs; - let options; - if (typeof arg1 === 'object' || typeof arg1 === 'undefined') { - attrs = arg1; + ): Promise { + let attrs: { [attr: string]: any } | null; + let options: SaveOptions | undefined; + if (typeof arg1 === 'object' || typeof arg1 === 'undefined' || arg1 == null) { + attrs = (arg1 as { [attr: string]: any }) || null; if (typeof arg2 === 'object') { options = arg2; } @@ -1317,7 +1338,7 @@ class ParseObject { } options = options || {}; - const saveOptions = {}; + const saveOptions: SaveOptions = {}; if (options.hasOwnProperty('useMasterKey')) { saveOptions.useMasterKey = !!options.useMasterKey; } @@ -1334,7 +1355,7 @@ class ParseObject { const unsaved = options.cascadeSave !== false ? unsavedChildren(this) : null; return controller.save(unsaved, saveOptions).then(() => { return controller.save(this, saveOptions); - }); + }) as Promise as Promise; } /** @@ -1359,7 +1380,7 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - async destroyEventually(options: RequestOptions): Promise { + async destroyEventually(options: RequestOptions): Promise { try { await this.destroy(options); } catch (e) { @@ -1385,9 +1406,9 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroy * completes. */ - destroy(options: RequestOptions): Promise { + destroy(options: RequestOptions): Promise { options = options || {}; - const destroyOptions = {}; + const destroyOptions: RequestOptions = {}; if (options.hasOwnProperty('useMasterKey')) { destroyOptions.useMasterKey = options.useMasterKey; } @@ -1400,7 +1421,7 @@ class ParseObject { if (!this.id) { return Promise.resolve(); } - return CoreManager.getObjectController().destroy(this, destroyOptions); + return CoreManager.getObjectController().destroy(this, destroyOptions) as Promise; } /** @@ -1552,7 +1573,7 @@ class ParseObject { * @returns {Parse.Object[]} */ static fetchAll(list: Array, options: RequestOptions = {}) { - const queryOptions = {}; + const queryOptions: RequestOptions = {}; if (options.hasOwnProperty('useMasterKey')) { queryOptions.useMasterKey = options.useMasterKey; } @@ -1662,10 +1683,8 @@ class ParseObject { * @static * @returns {Parse.Object[]} */ - static fetchAllIfNeeded(list: Array, options) { - options = options || {}; - - const queryOptions = {}; + static fetchAllIfNeeded(list: Array, options: ObjectFetchOptions = {}) { + const queryOptions: ObjectFetchOptions = {}; if (options.hasOwnProperty('useMasterKey')) { queryOptions.useMasterKey = options.useMasterKey; } @@ -1678,8 +1697,8 @@ class ParseObject { return CoreManager.getObjectController().fetch(list, false, queryOptions); } - static handleIncludeOptions(options) { - let include = []; + static handleIncludeOptions(options: { include?: string | string[] }) { + let include: string[] = []; if (Array.isArray(options.include)) { options.include.forEach(key => { if (Array.isArray(key)) { @@ -1689,7 +1708,7 @@ class ParseObject { } }); } else { - include.push(options.include); + include.push(options.include!); } return include; } @@ -1740,8 +1759,8 @@ class ParseObject { * @returns {Promise} A promise that is fulfilled when the destroyAll * completes. */ - static destroyAll(list: Array, options = {}) { - const destroyOptions = {}; + static destroyAll(list: Array, options: SaveOptions = {}) { + const destroyOptions: SaveOptions = {}; if (options.hasOwnProperty('useMasterKey')) { destroyOptions.useMasterKey = options.useMasterKey; } @@ -1775,8 +1794,8 @@ class ParseObject { * @static * @returns {Parse.Object[]} */ - static saveAll(list: Array, options: RequestOptions = {}) { - const saveOptions = {}; + static saveAll(list: Array, options: SaveOptions = {}) { + const saveOptions: SaveOptions = {}; if (options.hasOwnProperty('useMasterKey')) { saveOptions.useMasterKey = options.useMasterKey; } @@ -1806,7 +1825,7 @@ class ParseObject { * @static * @returns {Parse.Object} A Parse.Object reference. */ - static createWithoutData(id: string) { + static createWithoutData(id: string): ParseObject { const obj = new this(); obj.id = id; return obj; @@ -1822,13 +1841,13 @@ class ParseObject { * @static * @returns {Parse.Object} A Parse.Object reference */ - static fromJSON(json: any, override?: boolean, dirty?: boolean) { + static fromJSON(json: any, override?: boolean, dirty?: boolean): ParseObject { if (!json.className) { throw new Error('Cannot create an object without a className'); } const constructor = classMap[json.className]; const o = constructor ? new constructor(json.className) : new ParseObject(json.className); - const otherAttributes = {}; + const otherAttributes: AttributeMap = {}; for (const attr in json) { if (attr !== 'className' && attr !== '__type') { otherAttributes[attr] = json[attr]; @@ -1877,7 +1896,7 @@ class ParseObject { if (typeof constructor !== 'function') { throw new TypeError( 'You must register the subclass constructor. ' + - 'Did you attempt to register an instance of the subclass?' + 'Did you attempt to register an instance of the subclass?' ); } classMap[className] = constructor; @@ -1935,7 +1954,7 @@ class ParseObject { * this method. * @returns {Parse.Object} A new subclass of Parse.Object. */ - static extend(className: any, protoProps: any, classProps: any) { + static extend(className: any, protoProps?: any, classProps?: any) { if (typeof className !== 'string') { if (className && typeof className.className === 'string') { return ParseObject.extend(className.className, className, protoProps); @@ -1950,7 +1969,7 @@ class ParseObject { } let parentProto = ParseObject.prototype; - if (this.hasOwnProperty('__super__') && this.__super__) { + if (this.hasOwnProperty('__super__') && (this as any).__super__) { parentProto = this.prototype; } let ParseObjectSubclass = function (attributes, options) { @@ -1976,15 +1995,16 @@ class ParseObject { if (classMap[adjustedClassName]) { ParseObjectSubclass = classMap[adjustedClassName]; } else { - ParseObjectSubclass.extend = function (name, protoProps, classProps) { + // TODO: Maybe there is a more elegant solution to this? + (ParseObjectSubclass as any).extend = function (name: string, protoProps: any, classProps: any) { if (typeof name === 'string') { return ParseObject.extend.call(ParseObjectSubclass, name, protoProps, classProps); } return ParseObject.extend.call(ParseObjectSubclass, adjustedClassName, name, protoProps); }; - ParseObjectSubclass.createWithoutData = ParseObject.createWithoutData; - ParseObjectSubclass.className = adjustedClassName; - ParseObjectSubclass.__super__ = parentProto; + (ParseObjectSubclass as any).createWithoutData = ParseObject.createWithoutData; + (ParseObjectSubclass as any).className = adjustedClassName; + (ParseObjectSubclass as any).__super__ = parentProto; ParseObjectSubclass.prototype = Object.create(parentProto, { constructor: { value: ParseObjectSubclass, @@ -2195,17 +2215,19 @@ const DefaultController = { target: ParseObject | Array, forceFetch: boolean, options: RequestOptions - ): Promise | ParseObject> { + ): Promise | ParseObject | undefined> { const localDatastore = CoreManager.getLocalDatastore(); if (Array.isArray(target)) { if (target.length < 1) { return Promise.resolve([]); } - const objs = []; - const ids = []; - let className = null; - const results = []; - let error = null; + /** Resulting Parse.Objects that have data */ + const objs: ParseObject[] = []; + /** IDs to fetch */ + const ids: string[] = []; + let className: null | string = null; + const results: ParseObject[] = []; + let error: ParseError | null = null; target.forEach(el => { if (error) { return; @@ -2223,7 +2245,7 @@ const DefaultController = { error = new ParseError(ParseError.MISSING_OBJECT_ID, 'All objects must have an ID'); } if (forceFetch || !el.isDataAvailable()) { - ids.push(el.id); + ids.push(el.id!); // Already checked e.id above. objs.push(el); } results.push(el); @@ -2231,16 +2253,17 @@ const DefaultController = { if (error) { return Promise.reject(error); } - const query = new ParseQuery(className); + // Construct a ParseQuery that finds objects with matching IDs + const query = new ParseQuery(className!); query.containedIn('objectId', ids); if (options && options.include) { query.include(options.include); } query._limit = ids.length; - return query.find(options).then(async objects => { - const idMap = {}; + return query.find(options).then(async (objects: ParseObject[]) => { + const idMap: Record = {}; objects.forEach(o => { - idMap[o.id] = o; + idMap[o.id!] = o; }); for (let i = 0; i < objs.length; i++) { const obj = objs[i]; @@ -2253,7 +2276,7 @@ const DefaultController = { } } if (!singleInstance) { - // If single instance objects are disabled, we need to replace the + // If single instance objects are disabled, we need to replace the objects in the results array. for (let i = 0; i < results.length; i++) { const obj = results[i]; if (obj && obj.id && idMap[obj.id]) { @@ -2275,7 +2298,7 @@ const DefaultController = { ); } const RESTController = CoreManager.getRESTController(); - const params = {}; + const params: RequestOptions = {}; if (options && options.include) { params.include = options.include.join(); } @@ -2292,13 +2315,14 @@ const DefaultController = { return target; }); } - return Promise.resolve(); + // Not Array, and not ParseObject; return undefined/void. + return Promise.resolve(undefined); }, async destroy( target: ParseObject | Array, - options: RequestOptions - ): Promise | ParseObject> { + options: SaveOptions + ): Promise | ParseObject> { const batchSize = options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE'); const localDatastore = CoreManager.getLocalDatastore(); @@ -2308,7 +2332,7 @@ const DefaultController = { if (target.length < 1) { return Promise.resolve([]); } - const batches = [[]]; + const batches: ParseObject[][] = [[]]; target.forEach(obj => { if (!obj.id) { return; @@ -2323,7 +2347,7 @@ const DefaultController = { batches.pop(); } let deleteCompleted = Promise.resolve(); - const errors = []; + const errors: ParseError[] = []; batches.forEach(batch => { deleteCompleted = deleteCompleted.then(() => { return RESTController.request( @@ -2375,7 +2399,7 @@ const DefaultController = { return Promise.resolve(target); }, - save(target: ParseObject | Array, options: RequestOptions) { + save(target: ParseObject | Array | null, options: RequestOptions) { const batchSize = options && options.batchSize ? options.batchSize : CoreManager.get('REQUEST_BATCH_SIZE'); const localDatastore = CoreManager.getLocalDatastore(); @@ -2394,13 +2418,14 @@ const DefaultController = { let unsaved = target.concat(); for (let i = 0; i < target.length; i++) { - if (target[i] instanceof ParseObject) { - unsaved = unsaved.concat(unsavedChildren(target[i], true)); + const target_i = target[i]; + if (target_i instanceof ParseObject) { + unsaved = unsaved.concat(unsavedChildren(target_i, true)); } } unsaved = unique(unsaved); - const filesSaved: Array = []; + const filesSaved: Array | undefined> = []; let pending: Array = []; unsaved.forEach(el => { if (el instanceof ParseFile) { @@ -2411,14 +2436,14 @@ const DefaultController = { }); return Promise.all(filesSaved).then(() => { - let objectError = null; + let objectError: null | ParseError = null; return continueWhile( () => { return pending.length > 0; }, () => { - const batch = []; - const nextPending = []; + const batch: ParseObject[] = []; + const nextPending: ParseObject[] = []; pending.forEach(el => { if (allowCustomObjectId && Object.prototype.hasOwnProperty.call(el, 'id') && !el.id) { throw new ParseError( @@ -2442,11 +2467,11 @@ const DefaultController = { // Queue up tasks for each object in the batch. // When every task is ready, the API request will execute - const batchReturned = new resolvingPromise(); - const batchReady = []; - const batchTasks = []; + const batchReturned = resolvingPromise(); + const batchReady: ReturnType>[] = []; + const batchTasks: Promise[] = []; batch.forEach((obj, index) => { - const ready = new resolvingPromise(); + const ready = resolvingPromise(); batchReady.push(ready); const task = function () { ready.resolve(); @@ -2503,7 +2528,7 @@ const DefaultController = { for (const object of target) { // Make sure that it is a ParseObject before updating it into the localDataStore if (object instanceof ParseObject) { - await localDatastore._updateLocalIdForObject(mapIdForPin[object.id], object); + await localDatastore._updateLocalIdForObject(mapIdForPin[object.id!], object); await localDatastore._updateObjectIfPinned(object); } } diff --git a/src/Socket.weapp.js b/src/Socket.weapp.ts similarity index 64% rename from src/Socket.weapp.js rename to src/Socket.weapp.ts index d8d3884e7..239180300 100644 --- a/src/Socket.weapp.js +++ b/src/Socket.weapp.ts @@ -1,36 +1,51 @@ module.exports = class SocketWeapp { - constructor(serverURL) { + onopen: () => void; + onmessage: () => void; + onclose: () => void; + onerror: () => void; + + constructor(serverURL: string) { this.onopen = () => {}; this.onmessage = () => {}; this.onclose = () => {}; this.onerror = () => {}; + // @ts-ignore wx.onSocketOpen(() => { this.onopen(); }); + // @ts-ignore wx.onSocketMessage(msg => { + // @ts-ignore this.onmessage(msg); }); + // @ts-ignore wx.onSocketClose((event) => { + // @ts-ignore this.onclose(event); }); + // @ts-ignore wx.onSocketError(error => { + // @ts-ignore this.onerror(error); }); + // @ts-ignore wx.connectSocket({ url: serverURL, }); } send(data) { + // @ts-ignore wx.sendSocketMessage({ data }); } close() { + // @ts-ignore wx.closeSocket(); } }; diff --git a/src/StorageController.weapp.js b/src/StorageController.weapp.ts similarity index 78% rename from src/StorageController.weapp.js rename to src/StorageController.weapp.ts index 321172c4e..c987c3b40 100644 --- a/src/StorageController.weapp.js +++ b/src/StorageController.weapp.ts @@ -6,12 +6,14 @@ const StorageController = { async: 0, - getItem(path: string): ?string { + getItem(path: string): string | null { + // @ts-ignore return wx.getStorageSync(path); }, setItem(path: string, value: string) { try { + // @ts-ignore wx.setStorageSync(path, value); } catch (e) { // Quota exceeded @@ -19,15 +21,18 @@ const StorageController = { }, removeItem(path: string) { + // @ts-ignore wx.removeStorageSync(path); }, getAllKeys() { + // @ts-ignore const res = wx.getStorageInfoSync(); return res.keys; }, clear() { + // @ts-ignore wx.clearStorageSync(); }, }; diff --git a/src/Xhr.weapp.js b/src/Xhr.weapp.ts similarity index 81% rename from src/Xhr.weapp.js rename to src/Xhr.weapp.ts index cb9f90121..033fe5267 100644 --- a/src/Xhr.weapp.js +++ b/src/Xhr.weapp.ts @@ -1,4 +1,24 @@ module.exports = class XhrWeapp { + UNSENT: number; + OPENED: number; + HEADERS_RECEIVED: number; + LOADING: number; + DONE: number; + header: {}; + readyState: any; + status: number; + response: string; + responseType: string; + responseText: string; + responseHeader: {}; + method: string; + url: string; + onabort: () => void; + onprogress: () => void; + onerror: () => void; + onreadystatechange: () => void; + requestTask: any; + constructor() { this.UNSENT = 0; this.OPENED = 1; @@ -55,6 +75,7 @@ module.exports = class XhrWeapp { } send(data) { + // @ts-ignore this.requestTask = wx.request({ url: this.url, method: this.method, @@ -71,6 +92,7 @@ module.exports = class XhrWeapp { }, fail: err => { this.requestTask = null; + // @ts-ignore this.onerror(err); }, }); @@ -80,6 +102,7 @@ module.exports = class XhrWeapp { loaded: res.totalBytesWritten, total: res.totalBytesExpectedToWrite, }; + // @ts-ignore this.onprogress(event); }); } diff --git a/src/decode.js b/src/decode.ts similarity index 90% rename from src/decode.js rename to src/decode.ts index 557002015..4fc5efd6b 100644 --- a/src/decode.js +++ b/src/decode.ts @@ -1,7 +1,6 @@ /** * @flow */ -import ParseACL from './ParseACL'; // eslint-disable-line no-unused-vars import ParseFile from './ParseFile'; import ParseGeoPoint from './ParseGeoPoint'; import ParsePolygon from './ParsePolygon'; @@ -9,12 +8,13 @@ import ParseObject from './ParseObject'; import { opFromJSON } from './ParseOp'; import ParseRelation from './ParseRelation'; +/** Decodes values from storage type */ export default function decode(value: any): any { if (value === null || typeof value !== 'object' || value instanceof Date) { return value; } if (Array.isArray(value)) { - const dup = []; + const dup: any[] = []; value.forEach((v, i) => { dup[i] = decode(v); }); @@ -31,7 +31,7 @@ export default function decode(value: any): any { } if (value.__type === 'Relation') { // The parent and key fields will be populated by the parent - const relation = new ParseRelation(null, null); + const relation = new ParseRelation(null, null); // null, null; since tests expect this. relation.targetClassName = value.className; return relation; }