diff --git a/README.md b/README.md index 5111d1d52..42af3ed2a 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ Types are updated manually after every release. If a definition doesn't exist, p #### Core Manager -The SDK has a [Core Manager](src/CoreManager.js) that handles all configurations and controllers. These modules can be swapped out for customization before you initialize the SDK. For full list of all available modules take a look at the [Core Manager Documentation](src/CoreManager.js). +The SDK has a [Core Manager](src/CoreManager.ts) that handles all configurations and controllers. These modules can be swapped out for customization before you initialize the SDK. For full list of all available modules take a look at the [Core Manager Documentation](src/CoreManager.ts). ```js // Configuration example diff --git a/src/CoreManager.js b/src/CoreManager.ts similarity index 53% rename from src/CoreManager.js rename to src/CoreManager.ts index de5efba95..db639b55d 100644 --- a/src/CoreManager.js +++ b/src/CoreManager.ts @@ -1,155 +1,236 @@ -/* - * @flow - */ - 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, {SaveOptions} from './ParseObject'; +import type ParseObject from './ParseObject'; +import type { SaveOptions } from './ParseObject'; import type { QueryJSON } from './ParseQuery'; 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'; +import type LiveQueryClient from './LiveQueryClient'; +import type ParseSchema from './ParseSchema'; 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, + /** Returns promise which resolves with JobStatusId of the job */ + startJob: (name: string, data: any, options: RequestOptions) => Promise, }; type ConfigController = { - current: () => Promise, - get: () => Promise, - save: (attrs: { [key: string]: any }) => Promise, + current: () => Promise | ParseConfig, + 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?: FileSaveOptions) => 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 | null, options: RequestOptions) => Promise | ParseFile>, + destroy: (object: ParseObject | Array, options: RequestOptions) => Promise>, }; type ObjectStateController = { - getState: (obj: any) => ?State, + getState: (obj: any) => State | null, initializeState: (obj: any, initial?: State) => State, - removeState: (obj: any) => ?State, + 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, + 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) => 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, 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 EventuallyQueue = { - save: (object: ParseObject, serverOptions: SaveOptions) => Promise, - destroy: (object: ParseObject, serverOptions: RequestOptions) => Promise, + save: (object: ParseObject, serverOptions: SaveOptions) => Promise, + destroy: (object: ParseObject, serverOptions: RequestOptions) => Promise, poll: (ms: number) => void }; 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<{ results: ParseSchema[] }>, + 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 | 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 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: 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, - }; 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, + // Use for testing + // getRawStorage(): Promise, }; 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 | null, + currentUserAsync: () => 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: (user: ParseUser, options: RequestOptions) => Promise, + requestPasswordReset: (email: string, options: RequestOptions) => Promise, + updateUserOnDisk: (user: ParseUser) => Promise, + upgradeToRevocableSession: (user: ParseUser, 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 = { - 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 LiveQueryControllerType = { + setDefaultLiveQueryClient(liveQueryClient: LiveQueryClient): void; + 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; }; -type WebSocketController = { +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, @@ -171,11 +252,12 @@ type Config = { LocalDatastoreController?: LocalDatastoreController, UserController?: UserController, HooksController?: HooksController, - WebSocketController?: WebSocketController, + WebSocketController?: new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController, + LiveQueryController?: LiveQueryControllerType, + AsyncStorage?: AsyncStorageType }; -const config: Config & { [key: string]: mixed } = { - // Defaults +const config: Config & { [key: string]: any } = { IS_NODE: typeof process !== 'undefined' && !!process.versions && @@ -237,7 +319,7 @@ const CoreManager = { }, getAnalyticsController(): AnalyticsController { - return config['AnalyticsController']; + return config['AnalyticsController']!; }, setCloudController(controller: CloudController) { @@ -246,7 +328,7 @@ const CoreManager = { }, getCloudController(): CloudController { - return config['CloudController']; + return config['CloudController']!; }, setConfigController(controller: ConfigController) { @@ -255,7 +337,7 @@ const CoreManager = { }, getConfigController(): ConfigController { - return config['ConfigController']; + return config['ConfigController']!; }, setCryptoController(controller: CryptoController) { @@ -280,8 +362,17 @@ const CoreManager = { config['FileController'] = controller; }, + setEventuallyQueue(controller: EventuallyQueue) { + requireMethods('EventuallyQueue', ['poll', 'save', 'destroy'], controller); + config['EventuallyQueue'] = controller; + }, + + getEventuallyQueue(): EventuallyQueue { + return config['EventuallyQueue']!; + }, + getFileController(): FileController { - return config['FileController']; + return config['FileController']!; }, setInstallationController(controller: InstallationController) { @@ -290,7 +381,7 @@ const CoreManager = { }, getInstallationController(): InstallationController { - return config['InstallationController']; + return config['InstallationController']!; }, setLiveQuery(liveQuery: any) { @@ -307,7 +398,7 @@ const CoreManager = { }, getObjectController(): ObjectController { - return config['ObjectController']; + return config['ObjectController']!; }, setObjectStateController(controller: ObjectStateController) { @@ -338,7 +429,7 @@ const CoreManager = { }, getObjectStateController(): ObjectStateController { - return config['ObjectStateController']; + return config['ObjectStateController']!; }, setPushController(controller: PushController) { @@ -347,7 +438,7 @@ const CoreManager = { }, getPushController(): PushController { - return config['PushController']; + return config['PushController']!; }, setQueryController(controller: QueryController) { @@ -356,7 +447,7 @@ const CoreManager = { }, getQueryController(): QueryController { - return config['QueryController']; + return config['QueryController']!; }, setRESTController(controller: RESTController) { @@ -365,16 +456,7 @@ const CoreManager = { }, getRESTController(): RESTController { - return config['RESTController']; - }, - - setEventuallyQueue(controller: EventuallyQueue) { - requireMethods('EventuallyQueue', ['poll', 'save', 'destroy'], controller); - config['EventuallyQueue'] = controller; - }, - - getEventuallyQueue(): EventuallyQueue { - return config['EventuallyQueue']; + return config['RESTController']!; }, setSchemaController(controller: SchemaController) { @@ -387,7 +469,7 @@ const CoreManager = { }, getSchemaController(): SchemaController { - return config['SchemaController']; + return config['SchemaController']!; }, setSessionController(controller: SessionController) { @@ -396,7 +478,7 @@ const CoreManager = { }, getSessionController(): SessionController { - return config['SessionController']; + return config['SessionController']!; }, setStorageController(controller: StorageController) { @@ -426,7 +508,7 @@ const CoreManager = { }, getLocalDatastoreController(): LocalDatastoreController { - return config['LocalDatastoreController']; + return config['LocalDatastoreController']!; }, setLocalDatastore(store: any) { @@ -438,10 +520,10 @@ const CoreManager = { }, getStorageController(): StorageController { - return config['StorageController']; + return config['StorageController']!; }, - setAsyncStorage(storage: any) { + setAsyncStorage(storage: AsyncStorageType) { config['AsyncStorage'] = storage; }, @@ -449,12 +531,12 @@ const CoreManager = { return config['AsyncStorage']; }, - setWebSocketController(controller: WebSocketController) { + setWebSocketController(controller: new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController) { config['WebSocketController'] = controller; }, - getWebSocketController(): WebSocketController { - return config['WebSocketController']; + getWebSocketController(): new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController { + return config['WebSocketController']!; }, setUserController(controller: UserController) { @@ -481,10 +563,10 @@ const CoreManager = { }, getUserController(): UserController { - return config['UserController']; + return config['UserController']!; }, - setLiveQueryController(controller: any) { + setLiveQueryController(controller: LiveQueryControllerType) { requireMethods( 'LiveQueryController', ['setDefaultLiveQueryClient', 'getDefaultLiveQueryClient', '_clearCachedDefaultClient'], @@ -493,8 +575,8 @@ const CoreManager = { config['LiveQueryController'] = controller; }, - getLiveQueryController(): any { - return config['LiveQueryController']; + getLiveQueryController(): LiveQueryControllerType { + return config['LiveQueryController']!; }, setHooksController(controller: HooksController) { @@ -503,7 +585,7 @@ const CoreManager = { }, getHooksController(): HooksController { - return config['HooksController']; + return config['HooksController']!; }, }; diff --git a/src/Parse.ts b/src/Parse.ts index 4aa88dbd1..6692df3e3 100644 --- a/src/Parse.ts +++ b/src/Parse.ts @@ -21,7 +21,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' @@ -50,7 +50,10 @@ interface ParseType { Parse?: ParseType, Analytics: typeof Analytics, AnonymousUtils: typeof AnonymousUtils, - Cloud: typeof Cloud, + Cloud: typeof Cloud & { + /** only available in server environments */ + useMasterKey?: () => void + }, CLP: typeof CLP, CoreManager: typeof CoreManager, Config: typeof Config, @@ -63,7 +66,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, @@ -81,7 +84,7 @@ interface ParseType { Session: typeof Session, Storage: typeof Storage, User: typeof User, - LiveQuery: ParseLiveQuery, + LiveQuery: typeof ParseLiveQuery, LiveQueryClient: typeof LiveQueryClient, initialize(applicationId: string, javaScriptKey: string): void, @@ -106,7 +109,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, @@ -117,37 +120,37 @@ interface ParseType { const Parse: ParseType = { ACL: ACL, Analytics: Analytics, - AnonymousUtils: AnonymousUtils, + AnonymousUtils: AnonymousUtils, Cloud: Cloud, CLP: CLP, - CoreManager: CoreManager, - Config: Config, - Error: ParseError, + CoreManager: CoreManager, + Config: Config, + Error: ParseError, 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: ParseObject, 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, + 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, IndexedDB: undefined, Hooks: undefined, Parse: undefined, @@ -181,7 +184,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 */ } @@ -389,7 +392,7 @@ const Parse: ParseType = { return encode(value, disallowObjects); }, - _getInstallationId () { + _getInstallationId() { return CoreManager.getInstallationController().currentInstallationId(); }, /** @@ -418,7 +421,7 @@ const Parse: ParseType = { * @static * @returns {boolean} */ - isLocalDatastoreEnabled () { + isLocalDatastoreEnabled() { return this.LocalDatastore.isEnabled; }, /** @@ -446,7 +449,7 @@ const Parse: ParseType = { * * @static */ - enableEncryptedUser () { + enableEncryptedUser() { this.encryptedUser = true; }, @@ -456,7 +459,7 @@ const Parse: ParseType = { * @static * @returns {boolean} */ - isEncryptedUserEnabled () { + isEncryptedUserEnabled() { return this.encryptedUser; }, }; @@ -466,7 +469,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/ParseFile.js b/src/ParseFile.js index 1d7ff6945..491487ca7 100644 --- a/src/ParseFile.js +++ b/src/ParseFile.js @@ -18,6 +18,10 @@ if (process.env.PARSE_BUILD === 'weapp') { type Base64 = { base64: string }; type Uri = { uri: string }; type FileData = Array | Base64 | Blob | Uri; +export type FileSaveOptions = FullOptions & { + metadata?: { [key: string]: any }, + tags?: { [key: string]: any }, +}; export type FileSource = | { format: 'file', diff --git a/src/ParseHooks.js b/src/ParseHooks.js index 8a5982687..43375ba7a 100644 --- a/src/ParseHooks.js +++ b/src/ParseHooks.js @@ -2,6 +2,9 @@ import CoreManager from './CoreManager'; import decode from './decode'; import ParseError from './ParseError'; +export type HookDeclaration = { functionName: string, url: string } | { className: string, triggerName: string, url: string }; +export type HookDeleteArg = { functionName: string } | { className: string, triggerName: string }; + export function getFunctions() { return CoreManager.getHooksController().get('functions'); } diff --git a/src/ParseSession.ts b/src/ParseSession.ts index 51b001742..68cb8f398 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/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" ] } diff --git a/types/CoreManager.d.ts b/types/CoreManager.d.ts index c7a350aa4..2fa05b5d3 100644 --- a/types/CoreManager.d.ts +++ b/types/CoreManager.d.ts @@ -1,184 +1,285 @@ -// @ts-nocheck -export default CoreManager; -declare namespace CoreManager { - function get(key: string): any; - function set(key: string, value: any): void; - function setAnalyticsController(controller: AnalyticsController): void; - function getAnalyticsController(): AnalyticsController; - function setCloudController(controller: CloudController): void; - function getCloudController(): CloudController; - function setConfigController(controller: ConfigController): void; - function getConfigController(): ConfigController; - function setCryptoController(controller: CryptoController): void; - function getCryptoController(): CryptoController; - function setFileController(controller: FileController): void; - function getFileController(): FileController; - function setInstallationController(controller: InstallationController): void; - function getInstallationController(): InstallationController; - function setObjectController(controller: ObjectController): void; - function getObjectController(): ObjectController; - function setObjectStateController(controller: ObjectStateController): void; - function getObjectStateController(): ObjectStateController; - function setPushController(controller: PushController): void; - function getPushController(): PushController; - function setQueryController(controller: QueryController): void; - function getQueryController(): QueryController; - function setRESTController(controller: RESTController): void; - function getRESTController(): RESTController; - function setSchemaController(controller: SchemaController): void; - function getSchemaController(): SchemaController; - function setSessionController(controller: SessionController): void; - function getSessionController(): SessionController; - function setStorageController(controller: StorageController): void; - function setLocalDatastoreController(controller: LocalDatastoreController): void; - function getLocalDatastoreController(): LocalDatastoreController; - function setLocalDatastore(store: any): void; - function getLocalDatastore(): mixed; - function getStorageController(): StorageController; - function setAsyncStorage(storage: any): void; - function getAsyncStorage(): mixed; - function setWebSocketController(controller: WebSocketController): void; - function getWebSocketController(): WebSocketController; - function setUserController(controller: UserController): void; - function getUserController(): UserController; - function setLiveQueryController(controller: any): void; - function getLiveQueryController(): any; - function setHooksController(controller: HooksController): void; - function getHooksController(): HooksController; -} +import type { AttributeMap, ObjectCache, OpsMap, State } from './ObjectStateMutations'; +import type ParseFile from './ParseFile'; +import type { FileSaveOptions, FileSource } from './ParseFile'; +import type { Op } from './ParseOp'; +import type ParseObject from './ParseObject'; +import type { SaveOptions } from './ParseObject'; +import type { QueryJSON } from './ParseQuery'; +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'; +import type LiveQueryClient from './LiveQueryClient'; +import type ParseSchema from './ParseSchema'; type AnalyticsController = { track: (name: string, dimensions: { [key: string]: string; }) => Promise; }; type CloudController = { - run: (name: string, data: mixed, options: RequestOptions) => Promise; + run: (name: string, data: any, options: RequestOptions) => Promise; getJobsData: (options: RequestOptions) => Promise; - startJob: (name: string, data: mixed, options: RequestOptions) => Promise; + /** Returns promise which resolves with JobStatusId of the job */ + startJob: (name: string, data: any, options: RequestOptions) => Promise; }; type ConfigController = { - current: () => Promise; - get: () => Promise; + current: () => Promise | ParseConfig; + get: (opts?: RequestOptions) => Promise; save: (attrs: { [key: string]: any; - }) => Promise; + }, 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?: FileSaveOptions) => 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 | ParseObject[], forceFetch: boolean, options: RequestOptions) => Promise; - save: (object: ParseObject | (ParseFile | ParseObject)[], options: RequestOptions) => Promise; - destroy: (object: ParseObject | ParseObject[], options: RequestOptions) => Promise; + fetch: (object: ParseObject | Array, forceFetch: boolean, options: RequestOptions) => Promise; + save: (object: ParseObject | Array | null, options: RequestOptions) => Promise | ParseFile>; + destroy: (object: ParseObject | Array, options: RequestOptions) => Promise>; }; type ObjectStateController = { - getState: (obj: any) => State; + getState: (obj: any) => State | null; initializeState: (obj: any, initial?: State) => State; - removeState: (obj: any) => State; + removeState: (obj: any) => State | null; getServerData: (obj: any) => AttributeMap; setServerData: (obj: any, attributes: AttributeMap) => void; - getPendingOps: (obj: any) => OpsMap[]; - setPendingOp: (obj: any, attr: string, op: Op) => 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) => 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, 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 EventuallyQueue = { + save: (object: ParseObject, serverOptions: SaveOptions) => Promise; + destroy: (object: ParseObject, serverOptions: RequestOptions) => Promise; + poll: (ms: number) => void; }; 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; + 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; 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; + 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; + 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; + 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; + 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 WebSocketController = { +type UserController = { + setCurrentUser: (user: ParseUser) => 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; + become: (user: ParseUser, options: RequestOptions) => Promise; + hydrate: (user: ParseUser, userJSON: AttributeMap) => Promise; + logOut: (options: RequestOptions) => Promise; + me: (user: ParseUser, options: RequestOptions) => Promise; + requestPasswordReset: (email: string, options: RequestOptions) => Promise; + updateUserOnDisk: (user: ParseUser) => Promise; + upgradeToRevocableSession: (user: ParseUser, 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 = { + get: (type: string, functionName?: string, triggerName?: string) => Promise; + create: (hook: HookDeclaration) => Promise; + remove: (hook: HookDeleteArg) => Promise; + update: (hook: HookDeclaration) => Promise; + sendRequest?: (method: string, path: string, body?: any) => Promise; +}; +type LiveQueryControllerType = { + setDefaultLiveQueryClient(liveQueryClient: LiveQueryClient): void; + 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; - onclose: () => void; + onclose: (arg?: any) => void; onerror: (error: any) => void; send: (data: any) => void; close: () => 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: { - [key: string]: mixed; - }) => 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; +declare const CoreManager: { + get: (key: string) => any; + set: (key: string, value: any) => void; + setIfNeeded: (key: string, value: any) => any; + setAnalyticsController(controller: AnalyticsController): void; + getAnalyticsController(): AnalyticsController; + setCloudController(controller: CloudController): void; + getCloudController(): CloudController; + setConfigController(controller: ConfigController): void; + getConfigController(): ConfigController; + setCryptoController(controller: CryptoController): void; + getCryptoController(): CryptoController; + setEventEmitter(eventEmitter: any): void; + getEventEmitter(): any; + setFileController(controller: FileController): void; + setEventuallyQueue(controller: EventuallyQueue): void; + getEventuallyQueue(): EventuallyQueue; + getFileController(): FileController; + setInstallationController(controller: InstallationController): void; + getInstallationController(): InstallationController; + setLiveQuery(liveQuery: any): void; + getLiveQuery(): any; + setObjectController(controller: ObjectController): void; + getObjectController(): ObjectController; + setObjectStateController(controller: ObjectStateController): void; + getObjectStateController(): ObjectStateController; + setPushController(controller: PushController): void; + getPushController(): PushController; + setQueryController(controller: QueryController): void; + getQueryController(): QueryController; + setRESTController(controller: RESTController): void; + getRESTController(): RESTController; + setSchemaController(controller: SchemaController): void; + getSchemaController(): SchemaController; + setSessionController(controller: SessionController): void; + getSessionController(): SessionController; + setStorageController(controller: StorageController): void; + setLocalDatastoreController(controller: LocalDatastoreController): void; + getLocalDatastoreController(): LocalDatastoreController; + setLocalDatastore(store: any): void; + getLocalDatastore(): any; + getStorageController(): StorageController; + setAsyncStorage(storage: AsyncStorageType): void; + getAsyncStorage(): AsyncStorageType; + setWebSocketController(controller: new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController): void; + getWebSocketController(): new (url: string | URL, protocols?: string | string[] | undefined) => WebSocketController; + setUserController(controller: UserController): void; + getUserController(): UserController; + setLiveQueryController(controller: LiveQueryControllerType): void; + getLiveQueryController(): LiveQueryControllerType; + setHooksController(controller: HooksController): void; + getHooksController(): HooksController; }; +export default CoreManager; diff --git a/types/Parse.d.ts b/types/Parse.d.ts index db3020c86..ecb89e504 100644 --- a/types/Parse.d.ts +++ b/types/Parse.d.ts @@ -14,7 +14,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'; @@ -23,7 +23,7 @@ import Schema from './ParseSchema'; import Session from './ParseSession'; import Storage from './Storage'; import User from './ParseUser'; -import LiveQuery from './ParseLiveQuery'; +import ParseLiveQuery from './ParseLiveQuery'; import LiveQueryClient from './LiveQueryClient'; /** * Contains all Parse API classes and functions. @@ -38,7 +38,10 @@ interface ParseType { Parse?: ParseType; Analytics: typeof Analytics; AnonymousUtils: typeof AnonymousUtils; - Cloud: typeof Cloud; + Cloud: typeof Cloud & { + /** only available in server environments */ + useMasterKey?: () => void; + }; CLP: typeof CLP; CoreManager: typeof CoreManager; Config: typeof Config; @@ -51,7 +54,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; @@ -69,7 +72,7 @@ interface ParseType { Session: typeof Session; Storage: typeof Storage; User: typeof User; - LiveQuery: typeof LiveQuery; + LiveQuery: typeof ParseLiveQuery; LiveQueryClient: typeof LiveQueryClient; initialize(applicationId: string, javaScriptKey: string): void; _initialize(applicationId: string, javaScriptKey: string, masterKey?: string): void; @@ -92,7 +95,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;