From e99f4fb0e4c1c64a799e1cbe23d9654bd9a628a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Tue, 9 Jun 2020 11:01:31 +0200 Subject: [PATCH 01/30] Updating package locks from release From 9cfbf1cdead36418715635ccd4f407dffa560430 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 10 Jun 2020 09:49:43 +0200 Subject: [PATCH 02/30] Merging types and adjusting configs --- packages/realm-web/rollup.config.js | 5 +- packages/realm-web/src/User.ts | 35 +++++- .../src/transports/AuthenticatedTransport.ts | 2 +- packages/realm-web/tsconfig.build.json | 3 +- packages/realm-web/tsconfig.json | 3 +- tsconfig.json | 7 +- types/app.d.ts | 109 ++++++++++++++++-- types/bson.d.ts | 23 ++++ types/index.d.ts | 52 +-------- 9 files changed, 169 insertions(+), 70 deletions(-) create mode 100644 types/bson.d.ts diff --git a/packages/realm-web/rollup.config.js b/packages/realm-web/rollup.config.js index d55dc754ae..d3417a64de 100644 --- a/packages/realm-web/rollup.config.js +++ b/packages/realm-web/rollup.config.js @@ -48,7 +48,10 @@ export default [ output: { file: "dist/bundle.d.ts", format: "es", - intro: '/// ', + intro: ` + /// + /// + `, }, plugins: [dts(), resolve()], }, diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index feb931a5b4..f637d8db62 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -55,7 +55,10 @@ export interface UserControlHandle { /** * Representation of an authenticated user of an app. */ -export class User implements Realm.User { +export class User< + FunctionsFactoryType extends object = Realm.DefaultFunctionsFactory, + CustomDataType extends object = any +> implements Realm.User { /** * The app that this user is associated with. */ @@ -217,6 +220,18 @@ export class User implements Realm.User { return this._state; } + get customData(): CustomDataType { + throw new Error("Not yet implemented"); + } + + get functions(): FunctionsFactoryType & Realm.BaseFunctionsFactory { + throw new Error("Not yet implemented"); + } + + get apiKeys(): Realm.Auth.APIKeys { + throw new Error("Not yet implemented"); + } + /** * @returns Profile containing detailed information about the user. */ @@ -253,4 +268,22 @@ export class User implements Realm.User { // Update the state this._state = UserState.LoggedOut; } + + /** @inheritdoc */ + public async linkCredentials(credentials: Realm.Credentials) { + throw new Error("Not yet implemented"); + } + + public async refreshCustomData() { + await this.refreshAccessToken(); + return this.customData; + } + + public callFunction(name: string, ...args: any[]) { + return this.functions.callFunction(name, ...args); + } + + private async refreshAccessToken() { + throw new Error("Not yet implemented"); + } } diff --git a/packages/realm-web/src/transports/AuthenticatedTransport.ts b/packages/realm-web/src/transports/AuthenticatedTransport.ts index 4805f2b76e..ae278446a9 100644 --- a/packages/realm-web/src/transports/AuthenticatedTransport.ts +++ b/packages/realm-web/src/transports/AuthenticatedTransport.ts @@ -26,7 +26,7 @@ interface UserContext { /** * The currently active user */ - currentUser: Realm.User | null; + currentUser: Realm.User | null; } /** diff --git a/packages/realm-web/tsconfig.build.json b/packages/realm-web/tsconfig.build.json index 46e3c95f2d..5c5b57a385 100644 --- a/packages/realm-web/tsconfig.build.json +++ b/packages/realm-web/tsconfig.build.json @@ -9,6 +9,7 @@ }, "exclude": [ "src/**/*.test.ts", - "src/test/" + "src/test/", + "types/" ] } \ No newline at end of file diff --git a/packages/realm-web/tsconfig.json b/packages/realm-web/tsconfig.json index 202667d67d..9432b90650 100644 --- a/packages/realm-web/tsconfig.json +++ b/packages/realm-web/tsconfig.json @@ -24,5 +24,6 @@ }, "include": [ "src/**/*.ts" - ] + ], + "exclude": [] } \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 2e13f7d3db..19e9f9f115 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,5 +3,8 @@ "strict": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true - } -} + }, + "exclude": [ + "packages" + ] +} \ No newline at end of file diff --git a/types/app.d.ts b/types/app.d.ts index 52068d8e9f..e4a796496f 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -23,10 +23,6 @@ /// declare namespace Realm { - // See https://stackoverflow.com/a/51114250 on why we're importing the BSON types like this - type ObjectId = import("bson").ObjectId; - type Binary = import("bson").Binary; - namespace Credentials { /** * Payload sent when authenticating using the [Email/Password Provider](https://docs.mongodb.com/stitch/authentication/userpass/). @@ -123,6 +119,7 @@ declare namespace Realm { * A MongoDB Realm App. */ class App { + /** * */ @@ -194,11 +191,14 @@ declare namespace Realm { /** * Representation of an authenticated user of an app. */ - interface User { + class User< + FunctionsFactoryType extends object = DefaultFunctionsFactory, + CustomDataType extends object = any + > { /** * The automatically-generated internal ID of the user. */ - id: string; + readonly id: string; /** * The state of the user. @@ -206,22 +206,99 @@ declare namespace Realm { readonly state: UserState; // TODO: Populate the list of identities - // identities: UserIdentity[]; + // readonly identities: UserIdentity[]; /** * The access token used when requesting a new access token. */ - accessToken: string | null; + readonly accessToken: string | null; /** * The refresh token used when requesting a new access token. */ - refreshToken: string | null; + readonly refreshToken: string | null; + + /** + * You can store arbitrary data about your application users in a MongoDB collection and configure Stitch to automatically expose each user’s data in a field of their user object. + * For example, you might store a user’s preferred language, date of birth, or their local timezone. + * + * If this value has not been configured, it will be empty. + */ + readonly customData: CustomDataType; /** * A profile containing additional information about the user. */ readonly profile: UserProfile; + + /** + * Use this to call functions defined by the MongoDB Realm app, as this user. + */ + readonly functions: FunctionsFactoryType & BaseFunctionsFactory; + + /** + * This object allows API keys associated with the user to be retrieved, created, enabled and disabled. + */ + readonly apiKeys: Realm.Auth.APIKeys; + + /** + * Log out the user. + */ + logOut(): Promise; + + /** + * Link the user with a new identity represented by another set of credentials. + * + * @param credentials The credentials to use when linking. + */ + linkCredentials(credentials: Credentials): Promise; + + /** + * Call a remote MongoDB Realm function by it's name. + * Note: Consider using `functions[name]()` instead of calling this method. + * + * @example + * // These are all equivalent: + * await user.callFunction("doThing", [a1, a2, a3]); + * await user.functions.doThing(a1, a2, a3); + * await user.functions["doThing"](a1, a2, a3); + * + * @example + * // The methods returned from the functions object are bound, which is why it's okay to store the function in a variable before calling it: + * const doThing = user.functions.doThing; + * await doThing(a1); + * await doThing(a2); + * + * @param name Name of the function + * @param args Arguments passed to the function + */ + callFunction(name: string, ...args: any[]): Promise; + + /** + * Refresh the access token and derive custom data from it. + * + * @returns The newly fetched custom data. + */ + refreshCustomData(): Promise; + + /** + * Use the Push service to enable sending push messages to this user via Firebase Cloud Messaging (FCM). + * + * @returns An service client with methods to register and deregister the device on the user. + */ + push(serviceName: string): { + /** + * Register this device with the user. + * + * @param token A Firebase Cloud Messaging (FCM) token, retrieved via the firebase SDK. + */ + register(token: string): Promise, + + /** + * Deregister this device with the user, to disable sending messages to this device. + */ + deregister(): Promise, + }; } /** @@ -236,13 +313,21 @@ declare namespace Realm { Removed = "removed", } + /** + * The type of a user. + */ + enum UserType { + /** A normal end-user created this user */ + Normal = "normal", + /** The user was created by the server */ + Server = "server", + } + // TODO: Implement storing these identities on the user - /* interface UserIdentity { userId: string; providerType: string; } - */ /** * An extended profile with detailed information about the user. @@ -299,7 +384,7 @@ declare namespace Realm { * The type of user * // TODO: Determine the meaning of the different possibilities. */ - userType: "server" | "normal"; + type: UserType; } /** diff --git a/types/bson.d.ts b/types/bson.d.ts new file mode 100644 index 0000000000..56886bc218 --- /dev/null +++ b/types/bson.d.ts @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2020 Realm Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +//////////////////////////////////////////////////////////////////////////// + +declare namespace Realm { + // See https://stackoverflow.com/a/51114250 on why we're importing the BSON types like this + type ObjectId = import("bson").ObjectId; + type Binary = import("bson").Binary; +} diff --git a/types/index.d.ts b/types/index.d.ts index 0004d9a78f..7f84f25a0f 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -19,6 +19,7 @@ // TypeScript Version: 2.3.2 // With great contributions to @akim95 on github +/// /// declare namespace Realm { @@ -328,57 +329,6 @@ declare namespace Realm { readonly prototype: Results; }; - interface UserProfile { - name?: string; - email?: string; - pictureUrl?: string; - firstName?: string; - lastName?: string; - gender?: string; - birthday?: string; - minAge?: string; - maxAge?: string; - } - - class User { - readonly identity: string; - readonly token: string; - readonly isLoggedIn: boolean; - readonly state: UserState; - readonly customData: Object; - readonly profile: UserProfile; - - /** - * Convenience wrapper around call_function(name, [args]). - * - * @example - * // These are all equivalent: - * await user.call_function("do_thing", [a1, a2, a3]); - * await user.functions.do_thing(a1, a2, a3); - * await user.functions["do_thing"](a1, a2, a3); - * - * @example - * // It it legal to store the functions as first-class values: - * const do_thing = user.functions.do_thing; - * await do_thing(a1); - * await do_thing(a2); - */ - readonly functions: { - [name: string] : (...args: any[]) => Promise - }; - - logOut(): void; - linkCredentials(credentials: Credentials): Promise; - callFunction(name: string, args: any[]): Promise; - refreshCustomData(): Promise; - push(serviceName: string): { - register(token: string): Promise, - deregister(): Promise, - }; - - readonly apiKeys: Realm.Auth.APIKeys; - } - namespace Auth { class APIKeys { createAPIKey(name: string): Promise; From d1a6271c4310c2d148012e7331397f92f57aaca1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 10 Jun 2020 14:22:52 +0200 Subject: [PATCH 03/30] Fixed linting issues --- packages/realm-network-transport/.eslintignore | 1 + packages/realm-network-transport/package-lock.json | 2 +- packages/realm-web/.eslintignore | 2 ++ packages/realm-web/src/User.ts | 7 +++---- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/realm-network-transport/.eslintignore b/packages/realm-network-transport/.eslintignore index 178135c2b2..72760ebe4d 100644 --- a/packages/realm-network-transport/.eslintignore +++ b/packages/realm-network-transport/.eslintignore @@ -1 +1,2 @@ /dist/ +/types/ diff --git a/packages/realm-network-transport/package-lock.json b/packages/realm-network-transport/package-lock.json index 42fcbc837e..563c5e57a2 100644 --- a/packages/realm-network-transport/package-lock.json +++ b/packages/realm-network-transport/package-lock.json @@ -256,7 +256,7 @@ "dev": true }, "eslint": { - "version": "file:https:/registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", + "version": "file:../../node_modules/eslint", "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { diff --git a/packages/realm-web/.eslintignore b/packages/realm-web/.eslintignore index 178135c2b2..a3ef5b0a25 100644 --- a/packages/realm-web/.eslintignore +++ b/packages/realm-web/.eslintignore @@ -1 +1,3 @@ /dist/ +/types/generated/ +/types/realm/ diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index f637d8db62..7ce21f9fa9 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -100,9 +100,8 @@ export class User< /** * Log in and create a user * - * @param transport The transport to use when issuing requests + * @param app The app used when logging in the user * @param credentials Credentials to use when logging in - * @param app * @param fetchProfile Should the users profile be fetched? (default: true) */ public static async logIn( @@ -223,11 +222,11 @@ export class User< get customData(): CustomDataType { throw new Error("Not yet implemented"); } - + get functions(): FunctionsFactoryType & Realm.BaseFunctionsFactory { throw new Error("Not yet implemented"); } - + get apiKeys(): Realm.Auth.APIKeys { throw new Error("Not yet implemented"); } From d50dfebfdca9e9ae7443bc766699ad1ec4c54590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 11 Jun 2020 01:17:16 +0200 Subject: [PATCH 04/30] Merged the auth provider types --- .../src/auth-providers/ApiKeyAuthProvider.ts | 9 ++++----- .../EmailPasswordAuthProvider.ts | 2 +- types/app.d.ts | 2 +- types/auth-providers.d.ts | 18 +++++++++--------- types/index.d.ts | 19 ------------------- 5 files changed, 15 insertions(+), 35 deletions(-) diff --git a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts b/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts index 91dc738109..fc679a0913 100644 --- a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts +++ b/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts @@ -20,8 +20,7 @@ import { Transport } from "../transports"; import { deserialize } from "../utils/ejson"; /** @inheritdoc */ -export class ApiKeyAuthProvider - implements Realm.AuthProviders.ApiKeyAuthProvider { +export class ApiKeyAuthProvider implements Realm.Auth.ApiKeyProvider { /** * The transport used to send requests to services. */ @@ -38,7 +37,7 @@ export class ApiKeyAuthProvider } /** @inheritdoc */ - create(name: string): Promise { + create(name: string): Promise { return this.transport .fetch({ method: "POST", @@ -48,7 +47,7 @@ export class ApiKeyAuthProvider } /** @inheritdoc */ - get(keyId: Realm.ObjectId): Promise { + get(keyId: Realm.ObjectId): Promise { return this.transport .fetch({ method: "GET", @@ -58,7 +57,7 @@ export class ApiKeyAuthProvider } /** @inheritdoc */ - list(): Promise { + list(): Promise { return this.transport.fetch({ method: "GET" }).then(deserialize); } diff --git a/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts b/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts index 31b309696e..7f19555d35 100644 --- a/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts +++ b/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts @@ -20,7 +20,7 @@ import { Transport } from "../transports"; /** @inheritdoc */ export class EmailPasswordAuthProvider - implements Realm.AuthProviders.EmailPasswordAuthProvider { + implements Realm.Auth.EmailPasswordProvider { /** * The underlying transport. */ diff --git a/types/app.d.ts b/types/app.d.ts index e4a796496f..f6c2f31cbc 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -239,7 +239,7 @@ declare namespace Realm { /** * This object allows API keys associated with the user to be retrieved, created, enabled and disabled. */ - readonly apiKeys: Realm.Auth.APIKeys; + readonly apiKeys: Realm.Auth.ApiKeyProvider; /** * Log out the user. diff --git a/types/auth-providers.d.ts b/types/auth-providers.d.ts index 3d17a6eacb..1e07fe08e0 100644 --- a/types/auth-providers.d.ts +++ b/types/auth-providers.d.ts @@ -22,16 +22,16 @@ declare namespace Realm { */ interface AuthProviders { /** Authentication provider where users identify using email and password. */ - emailPassword: Realm.AuthProviders.EmailPasswordAuthProvider; + emailPassword: Realm.Auth.EmailPasswordProvider; /** Authentication provider where users identify using an API-key. */ - apiKey: Realm.AuthProviders.ApiKeyAuthProvider; + apiKey: Realm.Auth.ApiKeyProvider; } - namespace AuthProviders { + namespace Auth { /** * Authentication provider where users identify using email and password. */ - interface EmailPasswordAuthProvider { + class EmailPasswordProvider { /** * Register a new user. * @@ -92,7 +92,7 @@ declare namespace Realm { /** * The representation of an API-key stored in the service. */ - interface ApiKey { + type ApiKey = { /** * The internal identifier of the key. */ @@ -112,12 +112,12 @@ declare namespace Realm { * When disabled, the key cannot authenticate. */ disabled: boolean; - } + }; /** * Authentication provider where users identify using an API-key. */ - interface ApiKeyAuthProvider { + class ApiKeyProvider { /** * Creates an API key that can be used to authenticate as the current user. * @@ -130,12 +130,12 @@ declare namespace Realm { * * @param keyId the id of the API key to fetch. */ - get(keyId: ObjectId): Promise; + fetch(keyId: ObjectId): Promise; /** * Fetches the API keys associated with the current user. */ - list(): Promise; + fetchAll(): Promise; /** * Deletes an API key associated with the current user. diff --git a/types/index.d.ts b/types/index.d.ts index 7f84f25a0f..5cdc3da523 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -329,25 +329,6 @@ declare namespace Realm { readonly prototype: Results; }; - namespace Auth { - class APIKeys { - createAPIKey(name: string): Promise; - fetchAPIKey(id: string): Promise; - allAPIKeys(): Promise>; - deleteAPIKey(id: string): Promise; - enableAPIKey(id: string): Promise; - disableAPIKey(id: string): Promise; - } - - class EmailPassword { - registerEmail(email: string, password: string): Promise; - confirmUser(token: string, id: string): Promise; - resendConfirmationEmail(email: string): Promise; - sendResetPasswordEmail(email: string): Promise; - resetPassword(password: string, token: string, id: string): Promise; - } - } - interface UserMap { [identity: string]: User } From 6fb981bdd8a13e3ed32f8bf4109f7338a1e46b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 11 Jun 2020 01:52:03 +0200 Subject: [PATCH 05/30] Fixing the functions factory types --- packages/realm-web/src/App.ts | 5 +++-- packages/realm-web/src/User.ts | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/realm-web/src/App.ts b/packages/realm-web/src/App.ts index 8c2d3cd46c..3e96517bcd 100644 --- a/packages/realm-web/src/App.ts +++ b/packages/realm-web/src/App.ts @@ -37,10 +37,11 @@ export interface AppConfiguration extends Realm.AppConfiguration { * MongoDB Realm App */ export class App< - FunctionsFactoryType extends Realm.BaseFunctionsFactory = Realm.DefaultFunctionsFactory + FunctionsFactoryType extends object = Realm.DefaultFunctionsFactory > implements Realm.App { /** @inheritdoc */ - public readonly functions: FunctionsFactoryType; + public readonly functions: FunctionsFactoryType & + Realm.BaseFunctionsFactory; /** @inheritdoc */ public readonly services: Realm.Services; diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index 7ce21f9fa9..b38ecbea7f 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -105,7 +105,7 @@ export class User< * @param fetchProfile Should the users profile be fetched? (default: true) */ public static async logIn( - app: App, + app: App, credentials: Realm.Credentials, fetchProfile = true, ) { From 62337cf021e413b586a6dc5eda8893e4fa4e3782 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 11 Jun 2020 01:52:54 +0200 Subject: [PATCH 06/30] Fixed integration tests based on updated types --- .../src/api-key-auth-provider.test.ts | 2 +- .../src/email-password-auth-provider.test.ts | 2 +- packages/realm-web-integration-tests/src/user.test.ts | 4 ++-- packages/realm-web-integration-tests/src/utils.ts | 4 +--- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts b/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts index bb3b7dd1b3..7f51360675 100644 --- a/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts +++ b/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts @@ -30,7 +30,7 @@ describe("ApiKeyAuthProvider", () => { const credentials = Credentials.anonymous(); await app.logIn(credentials); // List all existing keys - const keys = await app.auth.apiKey.list(); + const keys = await app.auth.apiKey.fetchAll(); // console.log(keys); // Create an api key const key = await app.auth.apiKey.create("my-key"); diff --git a/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts b/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts index d213d1f12f..3d651203b7 100644 --- a/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts +++ b/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts @@ -36,7 +36,7 @@ describe("EmailPasswordAuthProvider", () => { // List all existing keys await app.auth.emailPassword.registerUser(email, password); // Authenticate - const newCredentials = Credentials.usernamePassword(email, password); + const newCredentials = Credentials.emailPassword(email, password); await app.logIn(newCredentials); }); }); diff --git a/packages/realm-web-integration-tests/src/user.test.ts b/packages/realm-web-integration-tests/src/user.test.ts index 1512919f85..0e449f8c03 100644 --- a/packages/realm-web-integration-tests/src/user.test.ts +++ b/packages/realm-web-integration-tests/src/user.test.ts @@ -32,8 +32,8 @@ describe("User", () => { expect(user.state).equals("active"); // Expect something of the user profile expect(user.profile.type).equals("normal"); - expect(Array.isArray(user.profile.identities)).equals(true); - expect(user.profile.identities.length).equals(1); + // TODO: expect(Array.isArray(user.profile.identities)).equals(true); + // TODO: expect(user.profile.identities.length).equals(1); expect(user.profile.name).equals(undefined); }); }); diff --git a/packages/realm-web-integration-tests/src/utils.ts b/packages/realm-web-integration-tests/src/utils.ts index 080cfda535..d5b1dd0f4c 100644 --- a/packages/realm-web-integration-tests/src/utils.ts +++ b/packages/realm-web-integration-tests/src/utils.ts @@ -22,9 +22,7 @@ import { App } from "realm-web"; declare const APP_ID: string; declare const BASE_URL: string; -export function createApp< - FunctionsFactoryType extends Realm.FunctionsFactory ->() { +export function createApp() { if (typeof APP_ID !== "string") { throw new Error("Expected a global APP_ID"); } From 384a36a13d71b01873c0f145d79f486fec8f59d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 11 Jun 2020 01:53:58 +0200 Subject: [PATCH 07/30] Made options optional when using the HTTP service --- types/services.d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/types/services.d.ts b/types/services.d.ts index f3ce8fb19d..7412f7d92d 100644 --- a/types/services.d.ts +++ b/types/services.d.ts @@ -378,7 +378,7 @@ declare namespace Realm { */ get( url: string, - options: HTTP.RequestOptions, + options?: HTTP.RequestOptions, ): Promise; /** @@ -390,7 +390,7 @@ declare namespace Realm { */ post( url: string, - options: HTTP.RequestOptions, + options?: HTTP.RequestOptions, ): Promise; /** @@ -402,7 +402,7 @@ declare namespace Realm { */ put( url: string, - options: HTTP.RequestOptions, + options?: HTTP.RequestOptions, ): Promise; /** @@ -414,7 +414,7 @@ declare namespace Realm { */ delete( url: string, - options: HTTP.RequestOptions, + options?: HTTP.RequestOptions, ): Promise; /** @@ -426,7 +426,7 @@ declare namespace Realm { */ head( url: string, - options: HTTP.RequestOptions, + options?: HTTP.RequestOptions, ): Promise; /** @@ -438,7 +438,7 @@ declare namespace Realm { */ patch( url: string, - options: HTTP.RequestOptions, + options?: HTTP.RequestOptions, ): Promise; } From 093ba4956758c5448ad45478aa616e57e05d0e9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 11 Jun 2020 01:30:18 +0200 Subject: [PATCH 08/30] Updated types related to auth providers --- packages/realm-web/src/User.ts | 2 +- packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index b38ecbea7f..77447a5a48 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -227,7 +227,7 @@ export class User< throw new Error("Not yet implemented"); } - get apiKeys(): Realm.Auth.APIKeys { + get apiKeys(): Realm.Auth.ApiKeyProvider { throw new Error("Not yet implemented"); } diff --git a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts b/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts index fc679a0913..5606b703e3 100644 --- a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts +++ b/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts @@ -47,7 +47,7 @@ export class ApiKeyAuthProvider implements Realm.Auth.ApiKeyProvider { } /** @inheritdoc */ - get(keyId: Realm.ObjectId): Promise { + fetch(keyId: Realm.ObjectId): Promise { return this.transport .fetch({ method: "GET", @@ -57,7 +57,7 @@ export class ApiKeyAuthProvider implements Realm.Auth.ApiKeyProvider { } /** @inheritdoc */ - list(): Promise { + fetchAll(): Promise { return this.transport.fetch({ method: "GET" }).then(deserialize); } From dedd8f63f5d699d9f9032c8a456d77d53503b909 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 17 Jun 2020 12:46:48 +0200 Subject: [PATCH 09/30] Delete the commented App class declaration --- types/index.d.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 5cdc3da523..d0357d4dbe 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -333,15 +333,6 @@ declare namespace Realm { [identity: string]: User } - //TODO: This clashes with app.d.ts. Remove or refactor - // class App { - // logIn(credentials: Credentials): Promise; - // allUsers(): UserMap; - // currentUser(): User | null; - // switchUser(user: User): void; - // removeUser(user: User): Promise; - // } - interface SyncError { name: string; message: string; From 60777ae8ff95d1e0ab102bd1f9a4b0b6f0962980 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 17 Jun 2020 12:48:49 +0200 Subject: [PATCH 10/30] Merge types and update code accordingly --- .../src/app.test.ts | 6 +- packages/realm-web/src/App.ts | 121 ++++++++---------- packages/realm-web/src/User.test.ts | 20 --- packages/realm-web/src/User.ts | 89 +++---------- packages/realm-web/src/UserProfile.ts | 4 +- .../auth-providers/ApiKeyAuthProvider.test.ts | 4 +- types/app.d.ts | 29 ++++- 7 files changed, 98 insertions(+), 175 deletions(-) diff --git a/packages/realm-web-integration-tests/src/app.test.ts b/packages/realm-web-integration-tests/src/app.test.ts index 837d90f9b3..49fd533364 100644 --- a/packages/realm-web-integration-tests/src/app.test.ts +++ b/packages/realm-web-integration-tests/src/app.test.ts @@ -50,12 +50,12 @@ describe("App#constructor", () => { expect(app.allUsers).deep.equals([user2, user1]); // Ensure that the two users are not one and the same expect(user1.id).to.not.equals(user2.id); - // Switch back to the first user, by object reference + // Switch back to the first user app.switchUser(user1); expect(app.currentUser).equals(user1); expect(app.allUsers).deep.equals([user1, user2]); - // Switch back to the second user, by user id - app.switchUser(user2.id); + // Switch back to the second user + app.switchUser(user2); expect(app.currentUser).equals(user2); expect(app.allUsers).deep.equals([user2, user1]); // Switch back to the first user and log out diff --git a/packages/realm-web/src/App.ts b/packages/realm-web/src/App.ts index 3e96517bcd..dde128c94f 100644 --- a/packages/realm-web/src/App.ts +++ b/packages/realm-web/src/App.ts @@ -19,7 +19,7 @@ import { NetworkTransport } from "realm-network-transport"; import { create as createFunctionsFactory } from "./FunctionsFactory"; -import { User, UserState, UserControlHandle } from "./User"; +import { User, UserState } from "./User"; import { AuthenticatedTransport, Transport, BaseTransport } from "./transports"; import { Credentials } from "./Credentials"; import { create as createServicesFactory } from "./services"; @@ -37,8 +37,9 @@ export interface AppConfiguration extends Realm.AppConfiguration { * MongoDB Realm App */ export class App< - FunctionsFactoryType extends object = Realm.DefaultFunctionsFactory -> implements Realm.App { + FunctionsFactoryType extends object = Realm.DefaultFunctionsFactory, + CustomDataType extends object = any +> implements Realm.App { /** @inheritdoc */ public readonly functions: FunctionsFactoryType & Realm.BaseFunctionsFactory; @@ -81,7 +82,7 @@ export class App< * A (reversed) stack of active and logged-out users. * Elements in the beginning of the array is considered more recent than the later elements. */ - private readonly users: UserControlHandle[] = []; + private readonly users: User[] = []; /** * Construct a Realm App, either from the Realm App id visible from the MongoDB Realm UI or a configuration. @@ -131,28 +132,15 @@ export class App< * * @param nextUser The user or id of the user to switch to */ - public switchUser(nextUser: User | string) { - if (typeof nextUser === "string") { - const handle = this.users.find(({ user: u }) => u.id === nextUser); - if (handle) { - this.switchUser(handle.user); - } else { - throw new Error( - `Failed to switch user (id = ${nextUser}) - did you log in?`, - ); - } - } else if (nextUser instanceof User) { - const index = this.users.findIndex(({ user }) => user === nextUser); - if (index >= 0) { - // Remove the user from the stack - const [handle] = this.users.splice(index, 1); - // Insert the user in the beginning of the stack - this.users.splice(0, 0, handle); - } else { - throw new Error("The user was not logged into this app"); - } + public switchUser(nextUser: User) { + const index = this.users.findIndex(u => u === nextUser); + if (index >= 0) { + // Remove the user from the stack + const [user] = this.users.splice(index, 1); + // Insert the user in the beginning of the stack + this.users.splice(0, 0, user); } else { - throw new Error("Expected a user id or a User instance"); + throw new Error("The user was not logged into this app"); } } @@ -163,45 +151,35 @@ export class App< * @param fetchProfile Should the users profile be fetched? (default: true) */ public async logIn(credentials: Realm.Credentials, fetchProfile = true) { - const handle: UserControlHandle = await User.logIn( - this, - credentials, - fetchProfile, - ); + const user: User< + FunctionsFactoryType, + CustomDataType + > = await User.logIn(this, credentials, fetchProfile); // Add the user at the top of the stack - this.users.splice(0, 0, handle); + this.users.splice(0, 0, user); // Return the user - return handle.user; + return user; } /** - * Log out a user - * - * @param userOrId The user or id of the user to log out (default: currentUser) + * @inheritdoc */ - public async logOut( - userOrId: Realm.User | string | null = this.currentUser, - ) { - const { user } = this.getUserHandle(userOrId); - await user.logOut(); + public async logOut() { + const user = this.currentUser; + if (user) { + await user.logOut(); + } } /** - * Remove a user entirely from the app (logs out the user if they're not already logged out) - * - * @param userOrId The user or id of the user to remove. + * @inheritdoc */ - public async removeUser(userOrId: Realm.User | string) { - const { user, controller } = this.getUserHandle(userOrId); - // If active - log out the user - if (user.state === UserState.Active) { - await this.logOut(user); - } - // Set the state of the user - controller.setState(UserState.Removed); + public async removeUser(user: User) { // Remove the user from the list of users - const index = this.users.findIndex(({ user: u }) => u === user); + const index = this.users.findIndex(u => u === user); this.users.splice(index, 1); + // Log out the user + await user.logOut(); // TODO: Delete any data / tokens which were persisted } @@ -210,15 +188,18 @@ export class App< * * @returns the currently active user or null. */ - public get currentUser(): Realm.User | null { - const activeUserHandles = this.users.filter( - ({ user }) => user.state === UserState.Active, + public get currentUser(): User< + FunctionsFactoryType, + CustomDataType + > | null { + const activeUsers = this.users.filter( + user => user.state === UserState.Active, ); - if (activeUserHandles.length === 0) { + if (activeUsers.length === 0) { return null; } else { // Current user is the top of the stack - return activeUserHandles[0].user; + return activeUsers[0]; } } @@ -229,13 +210,15 @@ export class App< * * @returns An array of users active or loggedout users (current user being the first). */ - public get allUsers(): Readonly { - const allUsers = this.users.map(({ user }) => user); - const activeUsers = allUsers.filter( - user => user.state === UserState.Active, + public get allUsers(): Readonly< + Realm.User[] + > { + // We need to peek into refresh tokens to avoid cyclic code + const activeUsers = this.users.filter( + user => user.refreshToken !== null, ); - const loggedOutUsers = allUsers.filter( - user => user.state === UserState.LoggedOut, + const loggedOutUsers = this.users.filter( + user => user.refreshToken === null, ); // Returning a freezed copy of the list of users to prevent outside changes return Object.freeze([...activeUsers, ...loggedOutUsers]); @@ -247,14 +230,12 @@ export class App< * @param userOrId A user object or user id * @returns A handle containing the user and it's controller. */ - private getUserHandle(userOrId: Realm.User | string | null) { - const handle = this.users.find(({ user }) => - typeof userOrId === "string" - ? user.id === userOrId - : user === userOrId, + private getUser(userOrId: Realm.User | string | null) { + const user = this.users.find(u => + typeof userOrId === "string" ? u.id === userOrId : u === userOrId, ); - if (handle) { - return handle; + if (user) { + return user; } else { throw new Error("Invalid user or user id"); } diff --git a/packages/realm-web/src/User.test.ts b/packages/realm-web/src/User.test.ts index 282b22baaa..507bbf3cad 100644 --- a/packages/realm-web/src/User.test.ts +++ b/packages/realm-web/src/User.test.ts @@ -76,10 +76,6 @@ describe("User", () => { id: "some-user-id", accessToken: "deadbeef", refreshToken: "very-refreshing", - onController: controller => { - controller.setAccessToken("new-access-token"); - controller.setState(UserState.Removed); - }, }); // Expect an exception if the profile was never fetched expect(() => { @@ -93,20 +89,4 @@ describe("User", () => { firstName: "John", }); }); - - it("provides a controller which state", () => { - const user = new User({ - app: new MockApp("my-mocked-app"), - id: "some-user-id", - accessToken: "deadbeef", - refreshToken: "very-refreshing", - onController: controller => { - controller.setAccessToken("new-access-token"); - controller.setState(UserState.Removed); - }, - }); - // Expect something about the user - expect(user.accessToken).equals("new-access-token"); - expect(user.state).equals("removed"); - }); }); diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index 77447a5a48..0669634a40 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -28,7 +28,6 @@ interface UserParameters { id: string; accessToken: string; refreshToken: string; - onController?: (controller: UserController) => void; } export enum UserState { @@ -42,16 +41,6 @@ export enum UserType { Server = "server", } -export interface UserController { - setAccessToken(token: string): void; - setState(state: UserState): void; -} - -export interface UserControlHandle { - user: User; - controller: UserController; -} - /** * Representation of an authenticated user of an app. */ @@ -62,40 +51,7 @@ export class User< /** * The app that this user is associated with. */ - public readonly app: App; - - /* - * The list of identities associated with this user. - * // TODO: Implement and test this ... - */ - // public readonly identities: Realm.UserIdentity[] = []; - - /** - * Create a user, returning both the user and a controller enabling updates to the user's internal state. - * - * @param parameters The parameters passed to the constructor. - * @returns an object containing the new user and its controller. - */ - public static create(parameters: UserParameters): UserControlHandle { - const { onController, ...otherParameters } = parameters; - let controller: UserController | undefined; - const user = new User({ - ...otherParameters, - onController: c => { - if (onController) { - onController(c); - } - controller = c; - }, - }); - if (controller) { - return { user, controller }; - } else { - throw new Error( - "Expected controllerReady to be called synchronously", - ); - } - } + public readonly app: App; /** * Log in and create a user @@ -104,8 +60,11 @@ export class User< * @param credentials Credentials to use when logging in * @param fetchProfile Should the users profile be fetched? (default: true) */ - public static async logIn( - app: App, + public static async logIn< + FunctionsFactoryType extends object, + CustomDataType extends object + >( + app: App, credentials: Realm.Credentials, fetchProfile = true, ) { @@ -134,7 +93,7 @@ export class User< throw new Error("Expected an refresh token in the response"); } // Create the user - const handle = User.create({ + const user = new User({ app, id: userId, accessToken, @@ -142,10 +101,10 @@ export class User< }); // If neeeded, fetch and set the profile on the user if (fetchProfile) { - await handle.user.refreshProfile(); + await user.refreshProfile(); } // Return the user handle - return handle; + return user; } private _id: string; @@ -155,13 +114,7 @@ export class User< private _state: Realm.UserState; private transport: AuthenticatedTransport; - public constructor({ - app, - id, - accessToken, - refreshToken, - onController, - }: UserParameters) { + public constructor({ app, id, accessToken, refreshToken }: UserParameters) { this.app = app; this._id = id; this._accessToken = accessToken; @@ -170,18 +123,6 @@ export class User< this.transport = new AuthenticatedTransport(app.baseTransport, { currentUser: this, }); - - // Create and expose the controller to the creator - if (onController) { - onController({ - setAccessToken: token => { - this._accessToken = token; - }, - setState: state => { - this._state = state; - }, - }); - } } /** @@ -215,8 +156,14 @@ export class User< * * @returns The current state of the user. */ - get state(): Realm.UserState { - return this._state; + get state(): UserState { + if (this.app.allUsers.indexOf(this) === -1) { + return UserState.Removed; + } else { + return this._refreshToken === null + ? UserState.LoggedOut + : UserState.Active; + } } get customData(): CustomDataType { diff --git a/packages/realm-web/src/UserProfile.ts b/packages/realm-web/src/UserProfile.ts index af6ce55064..71dfe1ae69 100644 --- a/packages/realm-web/src/UserProfile.ts +++ b/packages/realm-web/src/UserProfile.ts @@ -41,7 +41,7 @@ enum DataKey { const DATA_MAPPING: { [k in DataKey]: keyof UserProfile } = { [DataKey.NAME]: "name", [DataKey.EMAIL]: "email", - [DataKey.PICTURE]: "pictureURL", + [DataKey.PICTURE]: "pictureUrl", [DataKey.FIRST_NAME]: "firstName", [DataKey.LAST_NAME]: "lastName", [DataKey.GENDER]: "gender", @@ -59,7 +59,7 @@ export class UserProfile implements Realm.UserProfile { public readonly email?: string; /** @inheritdoc */ - public readonly pictureURL?: string; + public readonly pictureUrl?: string; /** @inheritdoc */ public readonly firstName?: string; diff --git a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts b/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts index 3f24cc1e21..6b56e96e2e 100644 --- a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts +++ b/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts @@ -72,7 +72,7 @@ describe("ApiKeyAuthProvider", () => { }, ]); const provider = new ApiKeyAuthProvider(transport); - const apiKey = await provider.get( + const apiKey = await provider.fetch( ObjectId.createFromHexString("deadbeefdeadbeefdeadbeef"), ); // Expect something of the key @@ -115,7 +115,7 @@ describe("ApiKeyAuthProvider", () => { ], ]); const provider = new ApiKeyAuthProvider(transport); - const apiKeys = await provider.list(); + const apiKeys = await provider.fetchAll(); // Expect something of the first key const [firstKey, secondKey] = apiKeys; expect(firstKey._id.toHexString()).equals("deadbeefdeadbeefdeadbee1"); diff --git a/types/app.d.ts b/types/app.d.ts index f6c2f31cbc..c4812a196c 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -118,7 +118,7 @@ declare namespace Realm { /** * A MongoDB Realm App. */ - class App { + class App { /** * @@ -148,29 +148,40 @@ declare namespace Realm { /** * The last user to log in or being switched to. */ - readonly currentUser: Realm.User | null; + readonly currentUser: User | null; /** * All authenticated users. */ - readonly allUsers: Readonly; + readonly allUsers: Readonly[]>; /** * Log in a user using a specific credential * * @param credentials the credentials to use when logging in */ - logIn(credentials: Credentials): Promise; + logIn(credentials: Credentials): Promise>; /** * Log out the currently authenticated user and clear any persisted authentication information. + * + * @returns A promise that resolves once the user has been logged out of the app. + * + * TODO: Realm JS does not (yet) implement this method. */ logOut(): Promise; /** - * Switch current user, from an instance of `Realm.User` or the string id of the user. + * Switch current user, from an instance of `User` or the string id of the user. */ - switchUser(user: User | string): void; + switchUser(user: User): void; + + /** + * Switch current user, from an instance of `User` or the string id of the user. + * + * @returns A promise that resolves once the user has been logged out and removed from the app. + */ + removeUser(user: User): Promise; } /** @@ -243,8 +254,12 @@ declare namespace Realm { /** * Log out the user. + * + * @returns A promise that resolves once the user has been logged out of the app. + * + * TODO: Realm JS does not (yet) return a promise here, instead `undefined` is returned. */ - logOut(): Promise; + logOut(): Promise | void; /** * Link the user with a new identity represented by another set of credentials. From f237a33922219d0b64deb0ae3d6a56dbbe2076ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 17 Jun 2020 12:53:14 +0200 Subject: [PATCH 11/30] Package-lock got updated --- packages/realm-network-transport/package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/realm-network-transport/package-lock.json b/packages/realm-network-transport/package-lock.json index 563c5e57a2..42fcbc837e 100644 --- a/packages/realm-network-transport/package-lock.json +++ b/packages/realm-network-transport/package-lock.json @@ -256,7 +256,7 @@ "dev": true }, "eslint": { - "version": "file:../../node_modules/eslint", + "version": "file:https:/registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", "dev": true, "requires": { From 52e20b9f7359c3b3a33cd6115c594069c0880c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 17 Jun 2020 13:04:43 +0200 Subject: [PATCH 12/30] Fixed logging out a logged out user --- packages/realm-web/src/User.ts | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index 0669634a40..1f1e502b0c 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -201,16 +201,18 @@ export class User< public async logOut() { // Invalidate the refresh token - await this.app.baseTransport.fetch({ - method: "DELETE", - path: "/auth/session", - headers: { - Authorization: `Bearer ${this._refreshToken}`, - }, - }); - // Forget the tokens - this._accessToken = null; - this._refreshToken = null; + if (this._refreshToken !== null) { + await this.app.baseTransport.fetch({ + method: "DELETE", + path: "/auth/session", + headers: { + Authorization: `Bearer ${this._refreshToken}`, + }, + }); + // Forget the tokens + this._accessToken = null; + this._refreshToken = null; + } // Update the state this._state = UserState.LoggedOut; } From c595141b4c215d59fd8ba81fa2d57373eab5846a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 17 Jun 2020 13:05:12 +0200 Subject: [PATCH 13/30] Commented out the App#logOut method --- types/app.d.ts | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/types/app.d.ts b/types/app.d.ts index c4812a196c..b23a2ddaac 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -162,14 +162,13 @@ declare namespace Realm { */ logIn(credentials: Credentials): Promise>; - /** - * Log out the currently authenticated user and clear any persisted authentication information. - * - * @returns A promise that resolves once the user has been logged out of the app. - * - * TODO: Realm JS does not (yet) implement this method. - */ - logOut(): Promise; + // TODO: Realm JS does not (yet) implement this method. Remove the comment once it does. + // /** + // * Log out the currently authenticated user and clear any persisted authentication information. + // * + // * @returns A promise that resolves once the user has been logged out of the app. + // */ + // logOut(): Promise; /** * Switch current user, from an instance of `User` or the string id of the user. @@ -177,7 +176,7 @@ declare namespace Realm { switchUser(user: User): void; /** - * Switch current user, from an instance of `User` or the string id of the user. + * Logs out and removes a user from the app. * * @returns A promise that resolves once the user has been logged out and removed from the app. */ From 66f28d9a09e373444cb68d22376d88abf9d003ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 17 Jun 2020 13:05:29 +0200 Subject: [PATCH 14/30] Adding removeUser to the tests --- packages/realm-web-integration-tests/src/app.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/realm-web-integration-tests/src/app.test.ts b/packages/realm-web-integration-tests/src/app.test.ts index 49fd533364..34ae06c6ef 100644 --- a/packages/realm-web-integration-tests/src/app.test.ts +++ b/packages/realm-web-integration-tests/src/app.test.ts @@ -64,5 +64,7 @@ describe("App#constructor", () => { await app.logOut(); expect(app.currentUser).equals(user2); expect(app.allUsers).deep.equals([user2, user1]); + await app.removeUser(user1); + expect(app.allUsers).deep.equals([user2]); }); }); From 3900e598cf56fc758ec15d7e438f65b62531ada5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Thu, 18 Jun 2020 10:47:50 +0200 Subject: [PATCH 15/30] Update types/app.d.ts Co-authored-by: Kenneth Geisshirt --- types/app.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/app.d.ts b/types/app.d.ts index b23a2ddaac..7e7b5cb973 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -229,7 +229,7 @@ declare namespace Realm { readonly refreshToken: string | null; /** - * You can store arbitrary data about your application users in a MongoDB collection and configure Stitch to automatically expose each user’s data in a field of their user object. + * You can store arbitrary data about your application users in a MongoDB collection and configure MongoDB Realm to automatically expose each user’s data in a field of their user object. * For example, you might store a user’s preferred language, date of birth, or their local timezone. * * If this value has not been configured, it will be empty. From 5e422714b6a1af7a635267265728c4e8b5976b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 19 Jun 2020 13:24:04 +0200 Subject: [PATCH 16/30] Removed "| void" --- types/app.d.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/types/app.d.ts b/types/app.d.ts index 7e7b5cb973..ec06af02e8 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -255,10 +255,8 @@ declare namespace Realm { * Log out the user. * * @returns A promise that resolves once the user has been logged out of the app. - * - * TODO: Realm JS does not (yet) return a promise here, instead `undefined` is returned. */ - logOut(): Promise | void; + logOut(): Promise; /** * Link the user with a new identity represented by another set of credentials. From 3d64511cb0eb5ba3ba94688823d282a9ce4658c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 19 Jun 2020 13:27:51 +0200 Subject: [PATCH 17/30] =?UTF-8?q?resendConfirmation=20=E2=86=92=20resendCo?= =?UTF-8?q?nfirmationEmail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../realm-web/src/auth-providers/EmailPasswordAuthProvider.ts | 2 +- types/auth-providers.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts b/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts index 7f19555d35..6a3684022c 100644 --- a/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts +++ b/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts @@ -55,7 +55,7 @@ export class EmailPasswordAuthProvider } /** @inheritdoc */ - resendConfirmation(email: string): Promise { + resendConfirmationEmail(email: string): Promise { return this.transport.fetch({ method: "POST", path: "/confirm/send", diff --git a/types/auth-providers.d.ts b/types/auth-providers.d.ts index 1e07fe08e0..67b1d78743 100644 --- a/types/auth-providers.d.ts +++ b/types/auth-providers.d.ts @@ -53,7 +53,7 @@ declare namespace Realm { * * @param email the email associated to resend the confirmation to. */ - resendConfirmation(email: string): Promise; + resendConfirmationEmail(email: string): Promise; /** * Complete resetting the password From 211462ad340d65e7883c0517ede5b1bf832e7556 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 19 Jun 2020 13:40:42 +0200 Subject: [PATCH 18/30] Removed logOut method from the `App` --- packages/realm-web-integration-tests/src/app.test.ts | 2 +- packages/realm-web/src/App.test.ts | 2 +- packages/realm-web/src/App.ts | 10 ---------- types/app.d.ts | 8 -------- 4 files changed, 2 insertions(+), 20 deletions(-) diff --git a/packages/realm-web-integration-tests/src/app.test.ts b/packages/realm-web-integration-tests/src/app.test.ts index 34ae06c6ef..049ffc0505 100644 --- a/packages/realm-web-integration-tests/src/app.test.ts +++ b/packages/realm-web-integration-tests/src/app.test.ts @@ -61,7 +61,7 @@ describe("App#constructor", () => { // Switch back to the first user and log out app.switchUser(user1); expect(app.currentUser).equals(user1); - await app.logOut(); + await user1.logOut(); expect(app.currentUser).equals(user2); expect(app.allUsers).deep.equals([user2, user1]); await app.removeUser(user1); diff --git a/packages/realm-web/src/App.test.ts b/packages/realm-web/src/App.test.ts index 0d02882f05..04f2d5d35c 100644 --- a/packages/realm-web/src/App.test.ts +++ b/packages/realm-web/src/App.test.ts @@ -163,7 +163,7 @@ describe("App", () => { // Expect that we logged in expect(app.currentUser).equals(user); expect(app.allUsers).deep.equals([user]); - await app.logOut(); + await user.logOut(); expect(app.currentUser).equals(null); expect(user.state).equals(UserState.LoggedOut); expect(user.state).equals("logged-out"); diff --git a/packages/realm-web/src/App.ts b/packages/realm-web/src/App.ts index dde128c94f..2dc5f595b9 100644 --- a/packages/realm-web/src/App.ts +++ b/packages/realm-web/src/App.ts @@ -161,16 +161,6 @@ export class App< return user; } - /** - * @inheritdoc - */ - public async logOut() { - const user = this.currentUser; - if (user) { - await user.logOut(); - } - } - /** * @inheritdoc */ diff --git a/types/app.d.ts b/types/app.d.ts index ec06af02e8..ae678b35dc 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -162,14 +162,6 @@ declare namespace Realm { */ logIn(credentials: Credentials): Promise>; - // TODO: Realm JS does not (yet) implement this method. Remove the comment once it does. - // /** - // * Log out the currently authenticated user and clear any persisted authentication information. - // * - // * @returns A promise that resolves once the user has been logged out of the app. - // */ - // logOut(): Promise; - /** * Switch current user, from an instance of `User` or the string id of the user. */ From 17faa28c3839bfbcecf6825c7f1dd3ecb969c0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 24 Jun 2020 11:29:37 +0200 Subject: [PATCH 19/30] Fixed App constructor type --- packages/realm-web/src/index.ts | 6 ++---- types/app.d.ts | 15 ++++++--------- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/packages/realm-web/src/index.ts b/packages/realm-web/src/index.ts index af9a5f2989..c847cfb232 100644 --- a/packages/realm-web/src/index.ts +++ b/packages/realm-web/src/index.ts @@ -21,7 +21,7 @@ import { App } from "./App"; const appCache: { [id: string]: Realm.App } = {}; /** - * Get or create a Realm App from an id. + * Get or create a singleton Realm App from an id. * * @param id The Realm App id visible from the MongoDB Realm UI or a configuration * @returns The Realm App instance. Calling this function multiple times with the same id will return the same instance. @@ -30,9 +30,7 @@ export function app(id: string) { if (id in appCache) { return appCache[id]; } else { - // Ensures the App has the correct constructor type signature - const AppConstructor: Realm.AppConstructor = App; - const instance = new AppConstructor(id); + const instance = new App(id); appCache[id] = instance; return instance; } diff --git a/types/app.d.ts b/types/app.d.ts index ae678b35dc..390589947b 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -106,19 +106,16 @@ declare namespace Realm { // TODO: Add providerCapabilities? } - /** - * The constructor of MongoDB Realm App. - */ - type AppConstructor = new < - FunctionsFactoryType extends object = DefaultFunctionsFactory - >( - idOrConfiguration: string | AppConfiguration, - ) => App; - /** * A MongoDB Realm App. */ class App { + /** + * Construct a MongoDB Realm App. + * + * @param idOrConfiguration The id string or configuration for the app. + */ + constructor(idOrConfiguration: string | AppConfiguration); /** * From ae2b6352fb20c6eb3e581ecc3b0375b8e7a8caac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Mon, 29 Jun 2020 10:09:05 +0200 Subject: [PATCH 20/30] Using unshift instead of splice where applicable --- packages/realm-web/src/App.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/realm-web/src/App.ts b/packages/realm-web/src/App.ts index 2dc5f595b9..7c29b1f404 100644 --- a/packages/realm-web/src/App.ts +++ b/packages/realm-web/src/App.ts @@ -138,7 +138,7 @@ export class App< // Remove the user from the stack const [user] = this.users.splice(index, 1); // Insert the user in the beginning of the stack - this.users.splice(0, 0, user); + this.users.unshift(user); } else { throw new Error("The user was not logged into this app"); } @@ -156,7 +156,7 @@ export class App< CustomDataType > = await User.logIn(this, credentials, fetchProfile); // Add the user at the top of the stack - this.users.splice(0, 0, user); + this.users.unshift(user); // Return the user return user; } From 25698f53ddb4de47a763547628e4fef573f763e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 1 Jul 2020 09:12:56 +0200 Subject: [PATCH 21/30] Adopted API to the latest proposal --- packages/realm-web/src/App.ts | 10 ++++----- packages/realm-web/src/User.ts | 2 +- ...uthProvider.test.ts => ApiKeyAuth.test.ts} | 16 +++++++------- .../{ApiKeyAuthProvider.ts => ApiKeyAuth.ts} | 2 +- ...rdAuthProvider.ts => EmailPasswordAuth.ts} | 3 +-- .../realm-web/src/auth-providers/index.ts | 21 ++----------------- types/app.d.ts | 8 +++---- types/auth-providers.d.ts | 8 +++---- 8 files changed, 26 insertions(+), 44 deletions(-) rename packages/realm-web/src/auth-providers/{ApiKeyAuthProvider.test.ts => ApiKeyAuth.test.ts} (93%) rename packages/realm-web/src/auth-providers/{ApiKeyAuthProvider.ts => ApiKeyAuth.ts} (97%) rename packages/realm-web/src/auth-providers/{EmailPasswordAuthProvider.ts => EmailPasswordAuth.ts} (97%) diff --git a/packages/realm-web/src/App.ts b/packages/realm-web/src/App.ts index 7c29b1f404..e62b8b5a0a 100644 --- a/packages/realm-web/src/App.ts +++ b/packages/realm-web/src/App.ts @@ -23,7 +23,7 @@ import { User, UserState } from "./User"; import { AuthenticatedTransport, Transport, BaseTransport } from "./transports"; import { Credentials } from "./Credentials"; import { create as createServicesFactory } from "./services"; -import { create as createAuthProviders } from "./auth-providers"; +import { EmailPasswordAuth } from "./auth-providers"; /** * Configuration to pass as an argument when constructing an app. @@ -47,9 +47,6 @@ export class App< /** @inheritdoc */ public readonly services: Realm.Services; - /** @inheritdoc */ - public readonly auth: Realm.AuthProviders; - /** @inheritdoc */ public readonly id: string; @@ -73,6 +70,9 @@ export class App< */ public readonly appTransport: Transport; + /** @inheritdoc */ + public readonly emailPasswordAuth: EmailPasswordAuth; + /** * This base route will be prefixed requests issued through by the base transport */ @@ -124,7 +124,7 @@ export class App< // Construct the services factory this.services = createServicesFactory(authTransport); // Construct the auth providers - this.auth = createAuthProviders(authTransport); + this.emailPasswordAuth = new EmailPasswordAuth(authTransport); } /** diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index 1f1e502b0c..d44686407a 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -174,7 +174,7 @@ export class User< throw new Error("Not yet implemented"); } - get apiKeys(): Realm.Auth.ApiKeyProvider { + get apiKeys(): Realm.Auth.ApiKeyAuth { throw new Error("Not yet implemented"); } diff --git a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts b/packages/realm-web/src/auth-providers/ApiKeyAuth.test.ts similarity index 93% rename from packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts rename to packages/realm-web/src/auth-providers/ApiKeyAuth.test.ts index 6b56e96e2e..286231ca9e 100644 --- a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.test.ts +++ b/packages/realm-web/src/auth-providers/ApiKeyAuth.test.ts @@ -19,7 +19,7 @@ import { expect } from "chai"; import { ObjectId } from "bson"; -import { ApiKeyAuthProvider } from "./ApiKeyAuthProvider"; +import { ApiKeyAuth } from "./ApiKeyAuth"; import { MockTransport } from "../test/MockTransport"; const DEFAULT_HEADERS = { @@ -27,7 +27,7 @@ const DEFAULT_HEADERS = { "Content-Type": "application/json", }; -describe("ApiKeyAuthProvider", () => { +describe("ApiKeyAuth", () => { it("can create an api key", async () => { const transport = new MockTransport([ { @@ -39,7 +39,7 @@ describe("ApiKeyAuthProvider", () => { disabled: true, }, ]); - const provider = new ApiKeyAuthProvider(transport); + const provider = new ApiKeyAuth(transport); const apiKey = await provider.create("my-key-name"); // Expect something of the newly created key expect(typeof apiKey._id).equals("object"); @@ -71,7 +71,7 @@ describe("ApiKeyAuthProvider", () => { disabled: true, }, ]); - const provider = new ApiKeyAuthProvider(transport); + const provider = new ApiKeyAuth(transport); const apiKey = await provider.fetch( ObjectId.createFromHexString("deadbeefdeadbeefdeadbeef"), ); @@ -114,7 +114,7 @@ describe("ApiKeyAuthProvider", () => { }, ], ]); - const provider = new ApiKeyAuthProvider(transport); + const provider = new ApiKeyAuth(transport); const apiKeys = await provider.fetchAll(); // Expect something of the first key const [firstKey, secondKey] = apiKeys; @@ -139,7 +139,7 @@ describe("ApiKeyAuthProvider", () => { it("can delete a key", async () => { const transport = new MockTransport([{}]); - const provider = new ApiKeyAuthProvider(transport); + const provider = new ApiKeyAuth(transport); await provider.delete( ObjectId.createFromHexString("deadbeefdeadbeefdeadbeef"), ); @@ -156,7 +156,7 @@ describe("ApiKeyAuthProvider", () => { it("can enable a key", async () => { const transport = new MockTransport([{}]); - const provider = new ApiKeyAuthProvider(transport); + const provider = new ApiKeyAuth(transport); await provider.enable( ObjectId.createFromHexString("deadbeefdeadbeefdeadbeef"), ); @@ -173,7 +173,7 @@ describe("ApiKeyAuthProvider", () => { it("can disable a key", async () => { const transport = new MockTransport([{}]); - const provider = new ApiKeyAuthProvider(transport); + const provider = new ApiKeyAuth(transport); await provider.disable( ObjectId.createFromHexString("deadbeefdeadbeefdeadbeef"), ); diff --git a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts b/packages/realm-web/src/auth-providers/ApiKeyAuth.ts similarity index 97% rename from packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts rename to packages/realm-web/src/auth-providers/ApiKeyAuth.ts index 5606b703e3..79ae533aa7 100644 --- a/packages/realm-web/src/auth-providers/ApiKeyAuthProvider.ts +++ b/packages/realm-web/src/auth-providers/ApiKeyAuth.ts @@ -20,7 +20,7 @@ import { Transport } from "../transports"; import { deserialize } from "../utils/ejson"; /** @inheritdoc */ -export class ApiKeyAuthProvider implements Realm.Auth.ApiKeyProvider { +export class ApiKeyAuth implements Realm.Auth.ApiKeyAuth { /** * The transport used to send requests to services. */ diff --git a/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts b/packages/realm-web/src/auth-providers/EmailPasswordAuth.ts similarity index 97% rename from packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts rename to packages/realm-web/src/auth-providers/EmailPasswordAuth.ts index 6a3684022c..86563612d6 100644 --- a/packages/realm-web/src/auth-providers/EmailPasswordAuthProvider.ts +++ b/packages/realm-web/src/auth-providers/EmailPasswordAuth.ts @@ -19,8 +19,7 @@ import { Transport } from "../transports"; /** @inheritdoc */ -export class EmailPasswordAuthProvider - implements Realm.Auth.EmailPasswordProvider { +export class EmailPasswordAuth implements Realm.Auth.EmailPasswordAuth { /** * The underlying transport. */ diff --git a/packages/realm-web/src/auth-providers/index.ts b/packages/realm-web/src/auth-providers/index.ts index 7aa5ace35b..50f8153074 100644 --- a/packages/realm-web/src/auth-providers/index.ts +++ b/packages/realm-web/src/auth-providers/index.ts @@ -16,22 +16,5 @@ // //////////////////////////////////////////////////////////////////////////// -import { Transport } from "../transports"; - -import { EmailPasswordAuthProvider } from "./EmailPasswordAuthProvider"; -import { ApiKeyAuthProvider } from "./ApiKeyAuthProvider"; - -// TODO: Consider if we should query the service for enabled authentication providers before creating clients. - -/** - * Create an app's authentication providers. - * - * @param transport The transport used when sending requests to the service. - * @returns An object with interfaces to all possible authentication provider the app might have. - */ -export function create(transport: Transport): Realm.AuthProviders { - return { - emailPassword: new EmailPasswordAuthProvider(transport), - apiKey: new ApiKeyAuthProvider(transport), - }; -} +export { EmailPasswordAuth } from "./EmailPasswordAuth"; +export { ApiKeyAuth } from "./ApiKeyAuth"; diff --git a/types/app.d.ts b/types/app.d.ts index 390589947b..68e0c45fe2 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -138,9 +138,9 @@ declare namespace Realm { services: Realm.Services; /** - * Perform operations on an app's authentication providers. + * Perform operations related to the email/password auth provider. */ - auth: Realm.AuthProviders; + emailPasswordAuth: Realm.Auth.EmailPasswordAuth; /** * The last user to log in or being switched to. @@ -236,9 +236,9 @@ declare namespace Realm { readonly functions: FunctionsFactoryType & BaseFunctionsFactory; /** - * This object allows API keys associated with the user to be retrieved, created, enabled and disabled. + * Perform operations related to the API-key auth provider. */ - readonly apiKeys: Realm.Auth.ApiKeyProvider; + readonly apiKeys: Realm.Auth.ApiKeyAuth; /** * Log out the user. diff --git a/types/auth-providers.d.ts b/types/auth-providers.d.ts index 67b1d78743..6bac741575 100644 --- a/types/auth-providers.d.ts +++ b/types/auth-providers.d.ts @@ -22,16 +22,16 @@ declare namespace Realm { */ interface AuthProviders { /** Authentication provider where users identify using email and password. */ - emailPassword: Realm.Auth.EmailPasswordProvider; + emailPassword: Realm.Auth.EmailPasswordAuth; /** Authentication provider where users identify using an API-key. */ - apiKey: Realm.Auth.ApiKeyProvider; + apiKey: Realm.Auth.ApiKeyAuth; } namespace Auth { /** * Authentication provider where users identify using email and password. */ - class EmailPasswordProvider { + class EmailPasswordAuth { /** * Register a new user. * @@ -117,7 +117,7 @@ declare namespace Realm { /** * Authentication provider where users identify using an API-key. */ - class ApiKeyProvider { + class ApiKeyAuth { /** * Creates an API key that can be used to authenticate as the current user. * From 9a2919e6482b141c1e59252e662238dcd3e9ad76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 1 Jul 2020 12:37:44 +0200 Subject: [PATCH 22/30] Fixed the realm-network-transport types --- packages/realm-network-transport/src/index.ts | 1 + packages/realm-web/src/test/MockNetworkTransport.ts | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/packages/realm-network-transport/src/index.ts b/packages/realm-network-transport/src/index.ts index a11642d761..6d064d1dc3 100644 --- a/packages/realm-network-transport/src/index.ts +++ b/packages/realm-network-transport/src/index.ts @@ -24,4 +24,5 @@ export { Method, SuccessCallback, ErrorCallback, + ResponseHandler, } from "./NetworkTransport"; diff --git a/packages/realm-web/src/test/MockNetworkTransport.ts b/packages/realm-web/src/test/MockNetworkTransport.ts index 5680669369..067b159d8b 100644 --- a/packages/realm-web/src/test/MockNetworkTransport.ts +++ b/packages/realm-web/src/test/MockNetworkTransport.ts @@ -18,9 +18,8 @@ import { NetworkTransport, - SuccessCallback, - ErrorCallback, Request, + ResponseHandler, } from "realm-network-transport"; /** @@ -68,9 +67,8 @@ export class MockNetworkTransport implements NetworkTransport { /** @inheritdoc */ fetchWithCallbacks( request: Request, - successCallback: SuccessCallback, - errorCallback: ErrorCallback, + handler: ResponseHandler, ) { - this.fetchAndParse(request).then(successCallback, errorCallback); + this.fetchAndParse(request).then(handler.onSuccess, handler.onError); } } From de28eb4f60d0112dff2dd55a1b4edb80896cffce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Wed, 1 Jul 2020 12:50:58 +0200 Subject: [PATCH 23/30] Updating integration tests --- .../src/api-key-auth-provider.test.ts | 8 ++++---- .../src/email-password-auth-provider.test.ts | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts b/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts index 7f51360675..c4bf4ff351 100644 --- a/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts +++ b/packages/realm-web-integration-tests/src/api-key-auth-provider.test.ts @@ -28,12 +28,12 @@ describe("ApiKeyAuthProvider", () => { const app = createApp(); // Login a user const credentials = Credentials.anonymous(); - await app.logIn(credentials); + const user = await app.logIn(credentials); // List all existing keys - const keys = await app.auth.apiKey.fetchAll(); - // console.log(keys); + const keys = await user.apiKeys.fetchAll(); + console.log(keys); // Create an api key - const key = await app.auth.apiKey.create("my-key"); + const key = await user.apiKeys.create("my-key"); // console.log(key); }); }); diff --git a/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts b/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts index 3d651203b7..a2f7ebc8ad 100644 --- a/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts +++ b/packages/realm-web-integration-tests/src/email-password-auth-provider.test.ts @@ -34,7 +34,7 @@ describe("EmailPasswordAuthProvider", () => { const email = `test-user-${runNumber}@testing.mongodb.com`; const password = "my-super-secret-password"; // List all existing keys - await app.auth.emailPassword.registerUser(email, password); + await app.emailPasswordAuth.registerUser(email, password); // Authenticate const newCredentials = Credentials.emailPassword(email, password); await app.logIn(newCredentials); From 9fdb8259205a3dfe8d3e55d2efb24aade438b39d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 10 Jul 2020 09:49:51 +0200 Subject: [PATCH 24/30] ApiKeyAuth renames (#3047) * Renamed UserAPIKeyProvider to ApiKeyAuth * Renaming instance methods * Moved from user.auth.apiKeys to user.apiKeys * Renamed js_user_apikey_provider.hpp to js_api_key_auth.hpp * Updated the jsdocs * Adding apiKeys to the browser proxy * Adding a note in the changelog --- CHANGELOG.md | 25 ++++++++ docs/sync.js | 16 ++--- lib/browser/user.js | 1 + lib/extensions.js | 4 +- lib/user.js | 11 ---- lib/user_apikey_provider_client.js | 24 ++++---- src/RealmJS.xcodeproj/project.pbxproj | 4 +- ...pikey_provider.hpp => js_api_key_auth.hpp} | 60 +++++++++---------- src/js_realm.hpp | 6 +- src/js_user.hpp | 10 ++-- tests/js/user-tests.js | 10 +++- 11 files changed, 95 insertions(+), 76 deletions(-) rename src/{js_user_apikey_provider.hpp => js_api_key_auth.hpp} (78%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 91fe83710a..718b47a06f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,28 @@ +x.x.x Release notes (yyyy-MM-dd) +============================================================= +NOTE: Support for syncing with realm.cloud.io and/or Realm Object Server has been replaced with support for syncing with MongoDB Realm Cloud. + +NOTE: This version bumps the Realm file format to version 11. It is not possible to downgrade to earlier versions. Older files will automatically be upgraded to the new file format. Files created by Realm JavaScript prior to v1.0.0, might not be upgradeable. Only [Realm Studio 10.0.0](https://github.com/realm/realm-studio/releases/tag/v10.0.0-beta.1) or later will be able to open the new file format. + +### Breaking changes +* `Realm.Auth.UserAPIKeyProvider` has been replaced by `Realm.Auth.ApiKeyProvider`. +* `user.auth.apiKeys` has been replaced by `user.apiKeys`. +* The instance methods on the ApiKeyAuth instance (`user.apiKeys`) have gotten their APIKey(s) suffix removed: Ex. `apiKeys.createAPIKey` has been replaced by `apiKeys.create`. + +### Enhancements +* None. + +### Fixed +* None. + +### Compatibility +* MongoDB Realm Cloud. +* APIs are backwards compatible with all previous releases of Realm JavaScript in the 10.x.y series. +* File format: generates Realms with format v11 (reads and upgrades file format v5 or later). + +### Internal +* None. + 10.0.0-beta.8 Release notes (2020-7-07) ============================================================= NOTE: Support for syncing with realm.cloud.io and/or Realm Object Server has been replaced with support for syncing with MongoDB Realm Cloud. diff --git a/docs/sync.js b/docs/sync.js index a248f5745b..1f156a0a7e 100644 --- a/docs/sync.js +++ b/docs/sync.js @@ -408,7 +408,7 @@ class EmailPassword { * client should only be used by an authenticated user. * @memberof Realm.Auth */ -class APIKeys { +class ApiKeyAuth { /** * Creates a user API key that can be used to authenticate as the current user. @@ -416,7 +416,7 @@ class APIKeys { * @param {string} name - The name of the API key to be created. * @returns {Promise} */ - createAPIKey(name) { } + create(name) { } /** * Fetches a user API key associated with the current user. @@ -424,14 +424,14 @@ class APIKeys { * @param {string} id - The id of the API key to fetch. * @returns {Promise} */ - fetchAPIKey(id) { } + fetch(id) { } /** * Fetches the user API keys associated with the current user. * * @returns {Promise} */ - allAPIKeys() { } + fetchAll() { } /** * Deletes a user API key associated with the current user. @@ -439,7 +439,7 @@ class APIKeys { * @param {string} id - The id of the API key to delete. * @returns {Promise} */ - deleteAPIKey(id) { } + delete(id) { } /** * Enables a user API key associated with the current user. @@ -447,7 +447,7 @@ class APIKeys { * @param {string} id - The id of the API key to enable. * @returns {Promise} */ - enableAPIKey(id) { } + enable(id) { } /** * Disables a user API key associated with the current user. @@ -455,7 +455,7 @@ class APIKeys { * @param {string} id - The id of the API key to disable. * @returns {Promise} */ - disableAPIKey(id) { } + disable(id) { } } @@ -528,7 +528,7 @@ class User { /** * Returns a provider to interact with API keys. - * @return {Realm.Auth.APIKeys} - the provider + * @return {Realm.Auth.ApiKeyAuth} - the provider */ apiKeys() { } diff --git a/lib/browser/user.js b/lib/browser/user.js index 619778b6e6..eceb1895ed 100644 --- a/lib/browser/user.js +++ b/lib/browser/user.js @@ -42,6 +42,7 @@ Object.defineProperties(User.prototype, { isLoggedIn: { get: getterForProperty('isLoggedIn') }, state: { get: getterForProperty('state') }, customData: { get: getterForProperty('customData') }, + apiKeys: { get: getterForProperty('apiKeys') }, }); export function createUser(realmId, info) { diff --git a/lib/extensions.js b/lib/extensions.js index 276f7f03b1..6b8dc28f6a 100644 --- a/lib/extensions.js +++ b/lib/extensions.js @@ -366,8 +366,8 @@ module.exports = function(realmConstructor, context) { let emailPasswordProviderMethods = require("./email_password_provider_client_methods"); Object.defineProperties(realmConstructor.Auth.EmailPasswordProvider.prototype, getOwnPropertyDescriptors(emailPasswordProviderMethods.instance)); - let userAPIKeyProviderMethods = require("./user_apikey_provider_client"); - Object.defineProperties(realmConstructor.Auth.UserAPIKeyProvider.prototype, getOwnPropertyDescriptors(userAPIKeyProviderMethods.instance)); + let apiKeyAuthMethods = require("./user_apikey_provider_client"); + Object.defineProperties(realmConstructor.Auth.ApiKeyAuth.prototype, getOwnPropertyDescriptors(apiKeyAuthMethods.instance)); realmConstructor.Sync.AuthError = require("./errors").AuthError; diff --git a/lib/user.js b/lib/user.js index 82a6f41477..a09bbb651a 100644 --- a/lib/user.js +++ b/lib/user.js @@ -95,17 +95,6 @@ const instanceMethods = { get functions() { return this._functionsOnService(undefined); }, - - get auth() { - const user = this; - return new Proxy({}, { - get(target, name) { - if (name === "apiKeys") { - return user._authApiKeys; - } - } - }); - } } const staticMethods = { diff --git a/lib/user_apikey_provider_client.js b/lib/user_apikey_provider_client.js index 2ec63b4ef7..18ae1840bc 100644 --- a/lib/user_apikey_provider_client.js +++ b/lib/user_apikey_provider_client.js @@ -21,28 +21,28 @@ const {promisify} = require("./utils.js"); const instanceMethods = { - createAPIKey(name) { - return promisify(cb => this._createAPIKey(name, cb)); + create(name) { + return promisify(cb => this._create(name, cb)); }, - fetchAPIKey(id) { - return promisify(cb => this._fetchAPIKey(id, cb)); + fetch(id) { + return promisify(cb => this._fetch(id, cb)); }, - fetchAPIKeys() { - return promisify(cb => this._fetchAPIKeys(cb)); + fetchAll() { + return promisify(cb => this._fetchAll(cb)); }, - deleteAPIKey(apiKeyId) { - return promisify(cb => this._deleteAPIKey(apiKeyId, cb)); + delete(apiKeyId) { + return promisify(cb => this._delete(apiKeyId, cb)); }, - enableAPIKey(apiKeyId) { - return promisify(cb => this._enableAPIKey(apiKeyId, cb)); + enable(apiKeyId) { + return promisify(cb => this._enable(apiKeyId, cb)); }, - disableAPIKey(apiKeyId) { - return promisify(cb => this._disableAPIKey(apiKeyId, cb)); + disable(apiKeyId) { + return promisify(cb => this._disable(apiKeyId, cb)); }, }; diff --git a/src/RealmJS.xcodeproj/project.pbxproj b/src/RealmJS.xcodeproj/project.pbxproj index 367fad5352..17e39b5e15 100644 --- a/src/RealmJS.xcodeproj/project.pbxproj +++ b/src/RealmJS.xcodeproj/project.pbxproj @@ -189,7 +189,7 @@ 42BD57AB24640A94008679D5 /* js_user.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_user.hpp; sourceTree = ""; }; 42BD57AC24640A94008679D5 /* js_network_transport.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_network_transport.hpp; sourceTree = ""; }; 42BD57AD24640A95008679D5 /* js_sync_util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_sync_util.hpp; sourceTree = ""; }; - 42BD57AE24640A95008679D5 /* js_user_apikey_provider.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_user_apikey_provider.hpp; sourceTree = ""; }; + 42BD57AE24640A95008679D5 /* js_api_key_auth.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_api_key_auth.hpp; sourceTree = ""; }; 42BD57AF24640AA8008679D5 /* keypath_helpers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = keypath_helpers.hpp; path = src/keypath_helpers.hpp; sourceTree = ""; }; 42BD57B024640AE4008679D5 /* generic_network_transport.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = generic_network_transport.hpp; path = src/sync/generic_network_transport.hpp; sourceTree = ""; }; 42BD57B124640AE4008679D5 /* app_credentials.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = app_credentials.hpp; path = src/sync/app_credentials.hpp; sourceTree = ""; }; @@ -360,7 +360,7 @@ 42BD57A824640A94008679D5 /* js_app.hpp */, 42BD57AC24640A94008679D5 /* js_network_transport.hpp */, 42BD57AD24640A95008679D5 /* js_sync_util.hpp */, - 42BD57AE24640A95008679D5 /* js_user_apikey_provider.hpp */, + 42BD57AE24640A95008679D5 /* js_api_key_auth.hpp */, 42BD57AB24640A94008679D5 /* js_user.hpp */, 42BD57AA24640A94008679D5 /* js_email_password_provider.hpp */, F62A35131C18E6E2004A917D /* iOS */, diff --git a/src/js_user_apikey_provider.hpp b/src/js_api_key_auth.hpp similarity index 78% rename from src/js_user_apikey_provider.hpp rename to src/js_api_key_auth.hpp index b5e4183f90..7bc2d18b85 100644 --- a/src/js_user_apikey_provider.hpp +++ b/src/js_api_key_auth.hpp @@ -29,19 +29,19 @@ using SharedUser = std::shared_ptr; using SharedApp = std::shared_ptr; template -class UserAPIKeyProviderClient : public app::App::UserAPIKeyProviderClient { +class ApiKeyAuth : public app::App::UserAPIKeyProviderClient { public: - UserAPIKeyProviderClient(app::App::UserAPIKeyProviderClient client, SharedUser user) : app::App::UserAPIKeyProviderClient(client), m_user(std::move(user)) {} - UserAPIKeyProviderClient(UserAPIKeyProviderClient &&) = default; + ApiKeyAuth(app::App::UserAPIKeyProviderClient client, SharedUser user) : app::App::UserAPIKeyProviderClient(client), m_user(std::move(user)) {} + ApiKeyAuth(ApiKeyAuth &&) = default; - UserAPIKeyProviderClient& operator=(UserAPIKeyProviderClient &&) = default; - UserAPIKeyProviderClient& operator=(UserAPIKeyProviderClient const&) = default; + ApiKeyAuth& operator=(ApiKeyAuth &&) = default; + ApiKeyAuth& operator=(ApiKeyAuth const&) = default; SharedUser m_user; }; template -class UserAPIKeyProviderClientClass : public ClassDefinition> { +class ApiKeyAuthClass : public ClassDefinition> { using GlobalContextType = typename T::GlobalContext; using ContextType = typename T::Context; using FunctionType = typename T::Function; @@ -55,7 +55,7 @@ class UserAPIKeyProviderClientClass : public ClassDefinition; public: - std::string const name = "UserAPIKeyProviderClient"; + std::string const name = "ApiKeyAuth"; static FunctionType create_constructor(ContextType); static ObjectType create_instance(ContextType, SharedApp, SharedUser); @@ -65,30 +65,30 @@ class UserAPIKeyProviderClientClass : public ClassDefinition const methods = { - {"_createAPIKey", wrap}, - {"_fetchAPIKey", wrap}, - {"_fetchAPIKeys", wrap}, - {"_deleteAPIKey", wrap}, - {"_enableAPIKey", wrap}, - {"_disableAPIKey", wrap}, + {"_create", wrap}, + {"_fetch", wrap}, + {"_fetchAll", wrap}, + {"_delete", wrap}, + {"_enable", wrap}, + {"_disable", wrap}, }; }; template -inline typename T::Function UserAPIKeyProviderClientClass::create_constructor(ContextType ctx) { - FunctionType constructor = ObjectWrap>::create_constructor(ctx); +inline typename T::Function ApiKeyAuthClass::create_constructor(ContextType ctx) { + FunctionType constructor = ObjectWrap>::create_constructor(ctx); return constructor; } template -typename T::Object UserAPIKeyProviderClientClass::create_instance(ContextType ctx, SharedApp app, SharedUser user) { - return create_object>(ctx, new UserAPIKeyProviderClient(app->provider_client(), user)); +typename T::Object ApiKeyAuthClass::create_instance(ContextType ctx, SharedApp app, SharedUser user) { + return create_object>(ctx, new ApiKeyAuth(app->provider_client(), user)); } template @@ -107,10 +107,10 @@ typename T::Object make_api_key(typename T::Context ctx, util::Optional -void UserAPIKeyProviderClientClass::create_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void ApiKeyAuthClass::create_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto name = Value::validated_to_string(ctx, args[0], "name"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); @@ -144,10 +144,10 @@ void UserAPIKeyProviderClientClass::create_api_key(ContextType ctx, ObjectTyp } template -void UserAPIKeyProviderClientClass::fetch_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void ApiKeyAuthClass::fetch_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto id = Value::validated_to_object_id(ctx, args[0], "id"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); @@ -181,10 +181,10 @@ void UserAPIKeyProviderClientClass::fetch_api_key(ContextType ctx, ObjectType } template -void UserAPIKeyProviderClientClass::fetch_api_keys(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void ApiKeyAuthClass::fetch_all_api_keys(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(1); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto callback = Value::validated_to_function(ctx, args[0], "callback"); Protected protected_ctx(Context::get_global_context(ctx)); @@ -255,10 +255,10 @@ app::App::UserAPIKey to_api_key(typename T::Context ctx, typename T::Object api_ } template -void UserAPIKeyProviderClientClass::delete_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void ApiKeyAuthClass::delete_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto api_key_id = Value::validated_to_object_id(ctx, args[0], "API key id"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); @@ -267,10 +267,10 @@ void UserAPIKeyProviderClientClass::delete_api_key(ContextType ctx, ObjectTyp } template -void UserAPIKeyProviderClientClass::enable_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void ApiKeyAuthClass::enable_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto api_key_id = Value::validated_to_object_id(ctx, args[0], "API key id"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); @@ -279,10 +279,10 @@ void UserAPIKeyProviderClientClass::enable_api_key(ContextType ctx, ObjectTyp } template -void UserAPIKeyProviderClientClass::disable_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void ApiKeyAuthClass::disable_api_key(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto api_key_id = Value::validated_to_object_id(ctx, args[0], "API key id"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); diff --git a/src/js_realm.hpp b/src/js_realm.hpp index 1bb1482efe..f891080ac2 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -34,7 +34,7 @@ #include "js_auth.hpp" #include "js_app_credentials.hpp" #include "js_email_password_provider.hpp" -#include "js_user_apikey_provider.hpp" +#include "js_api_key_auth.hpp" #include "sync/async_open_task.hpp" #include "sync/sync_config.hpp" #include "sync/sync_manager.hpp" @@ -470,8 +470,8 @@ inline typename T::Function RealmClass::create_constructor(ContextType ctx) { FunctionType email_password_provider_client_constructor = EmailPasswordProviderClientClass::create_constructor(ctx); Object::set_property(ctx, auth_constructor, "EmailPasswordProvider", email_password_provider_client_constructor, attributes); - FunctionType user_apikey_provider_client_constructor = UserAPIKeyProviderClientClass::create_constructor(ctx); - Object::set_property(ctx, auth_constructor, "UserAPIKeyProvider", user_apikey_provider_client_constructor, attributes); + FunctionType user_apikey_provider_client_constructor = ApiKeyAuthClass::create_constructor(ctx); + Object::set_property(ctx, auth_constructor, "ApiKeyAuth", user_apikey_provider_client_constructor, attributes); #endif if (getenv("REALM_DISABLE_SYNC_TO_DISK")) { diff --git a/src/js_user.hpp b/src/js_user.hpp index 0aa07541f2..29a5576bfa 100644 --- a/src/js_user.hpp +++ b/src/js_user.hpp @@ -22,7 +22,7 @@ #include "js_collection.hpp" #include "js_sync_util.hpp" #include "js_app_credentials.hpp" -#include "js_user_apikey_provider.hpp" +#include "js_api_key_auth.hpp" #include "sync/sync_config.hpp" #include "sync/sync_manager.hpp" @@ -76,7 +76,7 @@ class UserClass : public ClassDefinition> { static void is_logged_in(ContextType, ObjectType, ReturnValue &); static void get_state(ContextType, ObjectType, ReturnValue &); static void get_custom_data(ContextType, ObjectType, ReturnValue &); - static void get_auth_api_keys(ContextType, ObjectType, ReturnValue &); + static void get_api_keys(ContextType, ObjectType, ReturnValue &); PropertyMap const properties = { {"identity", {wrap, nullptr}}, @@ -85,7 +85,7 @@ class UserClass : public ClassDefinition> { {"isLoggedIn", {wrap, nullptr}}, {"state", {wrap, nullptr}}, {"customData", {wrap, nullptr}}, - {"_authApiKeys", {wrap, nullptr}}, + {"apiKeys", {wrap, nullptr}}, }; MethodMap const static_methods = { @@ -280,9 +280,9 @@ void UserClass::call_function(ContextType ctx, ObjectType this_object, Argume } template -void UserClass::get_auth_api_keys(ContextType ctx, ObjectType this_object, ReturnValue &return_value) { +void UserClass::get_api_keys(ContextType ctx, ObjectType this_object, ReturnValue &return_value) { auto user = get_internal>(ctx, this_object); - return_value.set(UserAPIKeyProviderClientClass::create_instance(ctx, user->m_app, *user)); + return_value.set(ApiKeyAuthClass::create_instance(ctx, user->m_app, *user)); } template diff --git a/tests/js/user-tests.js b/tests/js/user-tests.js index 0598de306e..e24a92579a 100644 --- a/tests/js/user-tests.js +++ b/tests/js/user-tests.js @@ -192,13 +192,17 @@ module.exports = { } }, - async testUserAPIKeyProvider() { + async testApiKeyAuth() { let app = new Realm.App(appConfig); let credentials = Realm.Credentials.anonymous(); let user = await app.logIn(credentials); - let provider = user.auth.apiKeys; - TestCase.assertTrue(provider instanceof Realm.Auth.UserAPIKeyProvider); + TestCase.assertTrue(user.apiKeys instanceof Realm.Auth.ApiKeyAuth); + + // TODO: Fix this to not respond with a 403 + // const keys = await user.apiKeys.fetchAll(); + // TestCase.assertTrue(Array.isArray(keys)); + await user.logOut(); }, From e267fc6da03b9d88bcb731e29ce23605af882883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 10 Jul 2020 12:29:35 +0200 Subject: [PATCH 25/30] EmailPasswordAuth renames (#3048) * Renamed to js_email_password_auth.hpp, email-password-auth-methods.js and api-key-auth-methods.js * Adding a note in the changelog * Updated docs * Renamed to EmailPasswordAuth --- CHANGELOG.md | 2 ++ binding.gyp | 2 +- docs/sync.js | 18 +++++------ ...ider_client.js => api-key-auth-methods.js} | 0 lib/app.js | 11 ------- ...hods.js => email-password-auth-methods.js} | 1 - lib/extensions.js | 6 ++-- src/RealmJS.xcodeproj/project.pbxproj | 4 +-- src/js_app.hpp | 10 +++--- ...rovider.hpp => js_email_password_auth.hpp} | 32 +++++++++---------- src/js_realm.hpp | 6 ++-- tests/js/user-tests.js | 16 +++++----- 12 files changed, 49 insertions(+), 59 deletions(-) rename lib/{user_apikey_provider_client.js => api-key-auth-methods.js} (100%) rename lib/{email_password_provider_client_methods.js => email-password-auth-methods.js} (99%) rename src/{js_email_password_provider.hpp => js_email_password_auth.hpp} (68%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 340bfb8389..3928c5f6e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ NOTE: This version bumps the Realm file format to version 11. It is not possible * `Realm.Auth.UserAPIKeyProvider` has been replaced by `Realm.Auth.ApiKeyProvider`. * `user.auth.apiKeys` has been replaced by `user.apiKeys`. * The instance methods on the ApiKeyAuth instance (`user.apiKeys`) have gotten their APIKey(s) suffix removed: Ex. `apiKeys.createAPIKey` has been replaced by `apiKeys.create`. +* `Realm.Auth.EmailPasswordProvider` has been replaced by `Realm.Auth.EmailPasswordAuth`. +* `app.auth.emailPassword` has been replaced by `user.emailPasswordAuth`. ### Enhancements * None. diff --git a/binding.gyp b/binding.gyp index 67cd533764..b78b824639 100644 --- a/binding.gyp +++ b/binding.gyp @@ -27,7 +27,7 @@ "src/js_app_credentials.hpp", "src/js_user.hpp", "src/js_network_transport.hpp", - "src/js_email_password_provider.hpp", + "src/js_email_password_auth.hpp", "src/node/sync_logger.cpp", "src/node/sync_logger.hpp", ] diff --git a/docs/sync.js b/docs/sync.js index 1820216004..cb9b9b510a 100644 --- a/docs/sync.js +++ b/docs/sync.js @@ -133,18 +133,18 @@ removeUser(user) { } /** - * Auth providers. Currently only `emailPassword` provider is support + * Client for the email/password authentication provider. * * @example * { - * let app = new Realm.App(config); - * let provider = app.auth.emailPassword; + * // Creating a new user, by registering via email & password + * const app = new Realm.App(config); + * await app.emailPasswordAuth.registerEmail('john@example.com', 'some-secure-password'); * } * - * @see Realm.Auth - * @see Realm.Auth.EmailPassword + * @type {Realm.Auth.EmailPasswordAuth} */ - get auth() { } + get emailPasswordAuth() { } } @@ -351,8 +351,8 @@ class Credentials { /** * A namespace for auth providers - * @see Realm.Auth.EmailPassword - * @see Realm.Auth.UserAPIKey + * @see Realm.Auth.EmailPasswordAuth + * @see Realm.Auth.ApiKeyAuth * @memberof Realm */ class Auth { @@ -363,7 +363,7 @@ class Auth { * Class for managing email/password for users * @memberof Realm.Auth */ -class EmailPassword { +class EmailPasswordAuth { /** * Registers a new email identity with the username/password provider, diff --git a/lib/user_apikey_provider_client.js b/lib/api-key-auth-methods.js similarity index 100% rename from lib/user_apikey_provider_client.js rename to lib/api-key-auth-methods.js diff --git a/lib/app.js b/lib/app.js index 9540c2e713..c585fc19c8 100644 --- a/lib/app.js +++ b/lib/app.js @@ -28,17 +28,6 @@ const instanceMethods = { removeUser() { return promisify(cb => this._removeUser(cb)); }, - - get auth() { - const app = this; - return new Proxy({}, { - get(target, name) { - if (name === "emailPassword") { - return app._authEmailPassword; - } - } - }); - } }; const staticMethods = { diff --git a/lib/email_password_provider_client_methods.js b/lib/email-password-auth-methods.js similarity index 99% rename from lib/email_password_provider_client_methods.js rename to lib/email-password-auth-methods.js index 2592fd7075..bd297d6b71 100644 --- a/lib/email_password_provider_client_methods.js +++ b/lib/email-password-auth-methods.js @@ -16,7 +16,6 @@ // //////////////////////////////////////////////////////////////////////////// -'use strict'; const {promisify} = require("./utils.js"); diff --git a/lib/extensions.js b/lib/extensions.js index 6b8dc28f6a..67e8053519 100644 --- a/lib/extensions.js +++ b/lib/extensions.js @@ -363,10 +363,10 @@ module.exports = function(realmConstructor, context) { let credentialMethods = require("./credentials"); Object.defineProperties(realmConstructor.Credentials, getOwnPropertyDescriptors(credentialMethods.static)) - let emailPasswordProviderMethods = require("./email_password_provider_client_methods"); - Object.defineProperties(realmConstructor.Auth.EmailPasswordProvider.prototype, getOwnPropertyDescriptors(emailPasswordProviderMethods.instance)); + let emailPasswordAuthMethods = require("./email-password-auth-methods"); + Object.defineProperties(realmConstructor.Auth.EmailPasswordAuth.prototype, getOwnPropertyDescriptors(emailPasswordAuthMethods.instance)); - let apiKeyAuthMethods = require("./user_apikey_provider_client"); + let apiKeyAuthMethods = require("./api-key-auth-methods"); Object.defineProperties(realmConstructor.Auth.ApiKeyAuth.prototype, getOwnPropertyDescriptors(apiKeyAuthMethods.instance)); diff --git a/src/RealmJS.xcodeproj/project.pbxproj b/src/RealmJS.xcodeproj/project.pbxproj index 17e39b5e15..fb9fe63fe2 100644 --- a/src/RealmJS.xcodeproj/project.pbxproj +++ b/src/RealmJS.xcodeproj/project.pbxproj @@ -185,7 +185,7 @@ 3FCE2A991F58BE3600D4855B /* feature_checks.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = feature_checks.hpp; path = "object-store/src/feature_checks.hpp"; sourceTree = SOURCE_ROOT; }; 42BD57A824640A94008679D5 /* js_app.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_app.hpp; sourceTree = ""; }; 42BD57A924640A94008679D5 /* js_app_credentials.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_app_credentials.hpp; sourceTree = ""; }; - 42BD57AA24640A94008679D5 /* js_email_password_provider.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_email_password_provider.hpp; sourceTree = ""; }; + 42BD57AA24640A94008679D5 /* js_email_password_auth.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_email_password_auth.hpp; sourceTree = ""; }; 42BD57AB24640A94008679D5 /* js_user.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_user.hpp; sourceTree = ""; }; 42BD57AC24640A94008679D5 /* js_network_transport.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_network_transport.hpp; sourceTree = ""; }; 42BD57AD24640A95008679D5 /* js_sync_util.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = js_sync_util.hpp; sourceTree = ""; }; @@ -362,7 +362,7 @@ 42BD57AD24640A95008679D5 /* js_sync_util.hpp */, 42BD57AE24640A95008679D5 /* js_api_key_auth.hpp */, 42BD57AB24640A94008679D5 /* js_user.hpp */, - 42BD57AA24640A94008679D5 /* js_email_password_provider.hpp */, + 42BD57AA24640A94008679D5 /* js_email_password_auth.hpp */, F62A35131C18E6E2004A917D /* iOS */, F6874A441CAD2ACD00EEEE36 /* JSC */, F6BCCFDF1C83809A00FE31AE /* lib */, diff --git a/src/js_app.hpp b/src/js_app.hpp index 0f23769f64..e0ef666d5f 100644 --- a/src/js_app.hpp +++ b/src/js_app.hpp @@ -29,7 +29,7 @@ #include "js_user.hpp" #include "js_app_credentials.hpp" #include "js_network_transport.hpp" -#include "js_email_password_provider.hpp" +#include "js_email_password_auth.hpp" using SharedApp = std::shared_ptr; using SharedUser = std::shared_ptr; @@ -60,11 +60,11 @@ class AppClass : public ClassDefinition { static FunctionType create_constructor(ContextType); static void get_app_id(ContextType, ObjectType, ReturnValue &); - static void get_auth_email_password(ContextType, ObjectType, ReturnValue &); + static void get_email_password_auth(ContextType, ObjectType, ReturnValue &); PropertyMap const properties = { {"id", {wrap, nullptr}}, - {"_authEmailPassword", {wrap, nullptr}}, + {"emailPasswordAuth", {wrap, nullptr}}, }; static void login(ContextType, ObjectType, Arguments&, ReturnValue&); @@ -296,9 +296,9 @@ void AppClass::remove_user(ContextType ctx, ObjectType this_object, Arguments } template -void AppClass::get_auth_email_password(ContextType ctx, ObjectType this_object, ReturnValue &return_value) { +void AppClass::get_email_password_auth(ContextType ctx, ObjectType this_object, ReturnValue &return_value) { auto app = *get_internal>(ctx, this_object); - return_value.set(EmailPasswordProviderClientClass::create_instance(ctx, app)); + return_value.set(EmailPasswordAuthClass::create_instance(ctx, app)); } } diff --git a/src/js_email_password_provider.hpp b/src/js_email_password_auth.hpp similarity index 68% rename from src/js_email_password_provider.hpp rename to src/js_email_password_auth.hpp index f3931d6279..09ab7a303e 100644 --- a/src/js_email_password_provider.hpp +++ b/src/js_email_password_auth.hpp @@ -27,7 +27,7 @@ namespace realm { namespace js { template -class EmailPasswordProviderClientClass : public ClassDefinition { +class EmailPasswordAuthClass : public ClassDefinition { using GlobalContextType = typename T::GlobalContext; using ContextType = typename T::Context; using FunctionType = typename T::Function; @@ -41,7 +41,7 @@ class EmailPasswordProviderClientClass : public ClassDefinition; public: - std::string const name = "EmailPasswordProviderClient"; + std::string const name = "EmailPasswordAuth"; static FunctionType create_constructor(ContextType); static ObjectType create_instance(ContextType, SharedApp); @@ -65,21 +65,21 @@ class EmailPasswordProviderClientClass : public ClassDefinition -inline typename T::Function EmailPasswordProviderClientClass::create_constructor(ContextType ctx) { - FunctionType constructor = ObjectWrap>::create_constructor(ctx); +inline typename T::Function EmailPasswordAuthClass::create_constructor(ContextType ctx) { + FunctionType constructor = ObjectWrap>::create_constructor(ctx); return constructor; } template -typename T::Object EmailPasswordProviderClientClass::create_instance(ContextType ctx, SharedApp app) { - return create_object>(ctx, new app::App::UsernamePasswordProviderClient(app->provider_client())); +typename T::Object EmailPasswordAuthClass::create_instance(ContextType ctx, SharedApp app) { + return create_object>(ctx, new app::App::UsernamePasswordProviderClient(app->provider_client())); } template -void EmailPasswordProviderClientClass::register_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void EmailPasswordAuthClass::register_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(3); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto email = Value::validated_to_string(ctx, args[0], "email"); auto password = Value::validated_to_string(ctx, args[1], "password"); @@ -89,10 +89,10 @@ void EmailPasswordProviderClientClass::register_email(ContextType ctx, Object } template -void EmailPasswordProviderClientClass::confirm_user(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void EmailPasswordAuthClass::confirm_user(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(3); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto token = Value::validated_to_string(ctx, args[0], "token"); auto token_id = Value::validated_to_string(ctx, args[1], "token_id"); @@ -102,10 +102,10 @@ void EmailPasswordProviderClientClass::confirm_user(ContextType ctx, ObjectTy } template -void EmailPasswordProviderClientClass::resend_confirmation_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void EmailPasswordAuthClass::resend_confirmation_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto email = Value::validated_to_string(ctx, args[0], "email"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); @@ -114,10 +114,10 @@ void EmailPasswordProviderClientClass::resend_confirmation_email(ContextType } template -void EmailPasswordProviderClientClass::send_reset_password_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void EmailPasswordAuthClass::send_reset_password_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(2); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto email = Value::validated_to_string(ctx, args[0], "email"); auto callback = Value::validated_to_function(ctx, args[1], "callback"); @@ -126,10 +126,10 @@ void EmailPasswordProviderClientClass::send_reset_password_email(ContextType } template -void EmailPasswordProviderClientClass::reset_password(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void EmailPasswordAuthClass::reset_password(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(4); - auto& client = *get_internal>(ctx, this_object); + auto& client = *get_internal>(ctx, this_object); auto password = Value::validated_to_string(ctx, args[0], "password"); auto token = Value::validated_to_string(ctx, args[1], "token"); diff --git a/src/js_realm.hpp b/src/js_realm.hpp index f891080ac2..06bd7c1e13 100644 --- a/src/js_realm.hpp +++ b/src/js_realm.hpp @@ -33,7 +33,7 @@ #include "js_app.hpp" #include "js_auth.hpp" #include "js_app_credentials.hpp" -#include "js_email_password_provider.hpp" +#include "js_email_password_auth.hpp" #include "js_api_key_auth.hpp" #include "sync/async_open_task.hpp" #include "sync/sync_config.hpp" @@ -467,8 +467,8 @@ inline typename T::Function RealmClass::create_constructor(ContextType ctx) { FunctionType auth_constructor = AuthClass::create_constructor(ctx); Object::set_property(ctx, realm_constructor, "Auth", auth_constructor, attributes); - FunctionType email_password_provider_client_constructor = EmailPasswordProviderClientClass::create_constructor(ctx); - Object::set_property(ctx, auth_constructor, "EmailPasswordProvider", email_password_provider_client_constructor, attributes); + FunctionType email_password_provider_client_constructor = EmailPasswordAuthClass::create_constructor(ctx); + Object::set_property(ctx, auth_constructor, "EmailPasswordAuth", email_password_provider_client_constructor, attributes); FunctionType user_apikey_provider_client_constructor = ApiKeyAuthClass::create_constructor(ctx); Object::set_property(ctx, auth_constructor, "ApiKeyAuth", user_apikey_provider_client_constructor, attributes); diff --git a/tests/js/user-tests.js b/tests/js/user-tests.js index e24a92579a..bdf07c53e5 100644 --- a/tests/js/user-tests.js +++ b/tests/js/user-tests.js @@ -91,7 +91,7 @@ function randomNonVerifiableEmail() { async function registerAndLogInEmailUser(app) { const validEmail = randomVerifiableEmail(); const validPassword = "test1234567890"; - await app.auth.emailPassword.registerEmail(validEmail, validPassword); + await app.emailPasswordAuth.registerEmail(validEmail, validPassword); let user = await app.logIn(Realm.Credentials.emailPassword(validEmail, validPassword)) assertIsUser(user); assertIsSameUser(user, app.currentUser()); @@ -140,10 +140,10 @@ module.exports = { }); }, - async testEmailPasswordProvider() { + async testEmailPasswordAuth() { let app = new Realm.App(appConfig); - let provider = app.auth.emailPassword; - TestCase.assertTrue(provider instanceof Realm.Auth.EmailPasswordProvider); + let provider = app.emailPasswordAuth; + TestCase.assertTrue(provider instanceof Realm.Auth.EmailPasswordAuth); }, async testRegisterAutoVerifyEmailPassword() { @@ -157,7 +157,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(invalidEmail, invalidPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - err = await TestCase.assertThrowsAsync(async() => app.auth.emailPassword.registerEmail(invalidEmail, invalidPassword)); + err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerEmail(invalidEmail, invalidPassword)); TestCase.assertEqual(err.message, "password must be between 6 and 128 characters"); err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user did not register @@ -166,7 +166,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(invalidEmail, validPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - err = await TestCase.assertThrowsAsync(async() => app.auth.emailPassword.registerEmail(invalidEmail, validPassword)); + err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerEmail(invalidEmail, validPassword)); TestCase.assertEqual(err.message, `failed to confirm user ${invalidEmail}`); err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user did not register @@ -175,7 +175,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(validEmail, invalidPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - err = await TestCase.assertThrowsAsync(async() => app.auth.emailPassword.registerEmail(validEmail, invalidPassword)); + err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerEmail(validEmail, invalidPassword)); TestCase.assertEqual(err.message, "password must be between 6 and 128 characters"); err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user did not register @@ -184,7 +184,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(validEmail, validPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - await app.auth.emailPassword.registerEmail(validEmail, validPassword); + await app.emailPasswordAuth.registerEmail(validEmail, validPassword); let user = await app.logIn(credentials) assertIsUser(user); assertIsSameUser(user, app.currentUser()); From 25778b4bd365ba6cc98869ffb76f9a368fdc50ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 10 Jul 2020 13:29:43 +0200 Subject: [PATCH 26/30] Moved push service to a seperate interface --- types/app.d.ts | 14 +------------- types/services.d.ts | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/types/app.d.ts b/types/app.d.ts index 68e0c45fe2..dba014ade0 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -287,19 +287,7 @@ declare namespace Realm { * * @returns An service client with methods to register and deregister the device on the user. */ - push(serviceName: string): { - /** - * Register this device with the user. - * - * @param token A Firebase Cloud Messaging (FCM) token, retrieved via the firebase SDK. - */ - register(token: string): Promise, - - /** - * Deregister this device with the user, to disable sending messages to this device. - */ - deregister(): Promise, - }; + push(serviceName: string): Realm.Services.Push; } /** diff --git a/types/services.d.ts b/types/services.d.ts index 7412f7d92d..119b626fe8 100644 --- a/types/services.d.ts +++ b/types/services.d.ts @@ -515,5 +515,22 @@ declare namespace Realm { body: Binary; } } + + /** + * Use the Push service to enable sending push messages to this user via Firebase Cloud Messaging (FCM). + */ + interface Push { + /** + * Register this device with the user. + * + * @param token A Firebase Cloud Messaging (FCM) token, retrieved via the firebase SDK. + */ + register(token: string): Promise, + + /** + * Deregister this device with the user, to disable sending messages to this device. + */ + deregister(): Promise, + } } } From 21dcc72afc73eabc32559dc23c879b005ae6a74d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 10 Jul 2020 13:30:11 +0200 Subject: [PATCH 27/30] Implemented a throwing push for a user --- packages/realm-web/src/User.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/realm-web/src/User.ts b/packages/realm-web/src/User.ts index d44686407a..967ff0288a 100644 --- a/packages/realm-web/src/User.ts +++ b/packages/realm-web/src/User.ts @@ -234,4 +234,8 @@ export class User< private async refreshAccessToken() { throw new Error("Not yet implemented"); } + + push(serviceName = ""): Realm.Services.Push { + throw new Error("Not yet implemented"); + } } From 28ccaa82f28cb57138d40df7a2242d2eb6a3f427 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 10 Jul 2020 13:33:48 +0200 Subject: [PATCH 28/30] Incorporated feedback --- packages/realm-web/src/App.test.ts | 53 ++++++++++++++++++++++++++++++ packages/realm-web/src/App.ts | 16 +++++---- types/app.d.ts | 6 ++-- 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/packages/realm-web/src/App.test.ts b/packages/realm-web/src/App.test.ts index 04f2d5d35c..f85d01bc23 100644 --- a/packages/realm-web/src/App.test.ts +++ b/packages/realm-web/src/App.test.ts @@ -232,6 +232,59 @@ describe("App", () => { ]); }); + it("throws if asked to switch to or remove an unknown user", async () => { + const transport = new MockNetworkTransport([ + { + user_id: "totally-valid-user-id", + access_token: "deadbeef", + refresh_token: "very-refreshing", + }, + ]); + const app = new App({ + id: "default-app-id", + transport, + baseUrl: "http://localhost:1337", + }); + const credentials = Credentials.anonymous(); + const user = await app.logIn(credentials, false); + // Expect that we logged in + expect(app.currentUser).equals(user); + expect(app.allUsers).deep.equals([user]); + const anotherUser = {} as User; + // Switch + try { + await app.switchUser(anotherUser); + throw new Error("Expected an exception"); + } catch (err) { + expect(err.message).equals( + "The user was never logged into this app", + ); + } + // Remove + try { + await app.removeUser(anotherUser); + throw new Error("Expected an exception"); + } catch (err) { + expect(err.message).equals( + "The user was never logged into this app", + ); + } + // Expect the first user to remain logged in and known to the app + expect(app.currentUser).equals(user); + expect(app.allUsers).deep.equals([user]); + expect(user.state).equals("active"); + // Assume the correct requests made it to the transport + expect(transport.requests).deep.equals([ + { + method: "POST", + url: + "http://localhost:1337/api/client/v2.0/app/default-app-id/auth/providers/anon-user/login", + body: {}, + headers: DEFAULT_HEADERS, + }, + ]); + }); + it("expose a callable functions factory", async () => { const transport = new MockNetworkTransport([ { diff --git a/packages/realm-web/src/App.ts b/packages/realm-web/src/App.ts index e62b8b5a0a..fcea102da7 100644 --- a/packages/realm-web/src/App.ts +++ b/packages/realm-web/src/App.ts @@ -134,14 +134,13 @@ export class App< */ public switchUser(nextUser: User) { const index = this.users.findIndex(u => u === nextUser); - if (index >= 0) { - // Remove the user from the stack - const [user] = this.users.splice(index, 1); - // Insert the user in the beginning of the stack - this.users.unshift(user); - } else { - throw new Error("The user was not logged into this app"); + if (index === -1) { + throw new Error("The user was never logged into this app"); } + // Remove the user from the stack + const [user] = this.users.splice(index, 1); + // Insert the user in the beginning of the stack + this.users.unshift(user); } /** @@ -167,6 +166,9 @@ export class App< public async removeUser(user: User) { // Remove the user from the list of users const index = this.users.findIndex(u => u === user); + if (index === -1) { + throw new Error("The user was never logged into this app"); + } this.users.splice(index, 1); // Log out the user await user.logOut(); diff --git a/types/app.d.ts b/types/app.d.ts index dba014ade0..be2eb9b4ee 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -248,14 +248,14 @@ declare namespace Realm { logOut(): Promise; /** - * Link the user with a new identity represented by another set of credentials. + * Link the user with an identity represented by another set of credentials. * * @param credentials The credentials to use when linking. */ linkCredentials(credentials: Credentials): Promise; /** - * Call a remote MongoDB Realm function by it's name. + * Call a remote MongoDB Realm function by its name. * Note: Consider using `functions[name]()` instead of calling this method. * * @example @@ -386,7 +386,7 @@ declare namespace Realm { */ interface BaseFunctionsFactory { /** - * Call a remote MongoDB Realm function by it's name. + * Call a remote MongoDB Realm function by its name. * Consider using `functions[name]()` instead of calling this method. * * @param name Name of the function From e98771d9747cf09c6771b3af2183d80d9c1f4ec7 Mon Sep 17 00:00:00 2001 From: Kenneth Geisshirt Date: Fri, 10 Jul 2020 14:01:56 +0200 Subject: [PATCH 29/30] v10 refactoring (#2996) * registerEmail -> registerUser * Realm.User.identity -> Realm.User.id. Realm.User.token -> Realm.User.accessToken. Add Realm.User.refreshToken. * Turn Realm.App.{currentUser, allUsers} to an instance property * Add Realm.Auth.EmailPassword.callResetPasswordFunction * Wrongly merged --- CHANGELOG.md | 6 ++- docs/sync.js | 34 +++++++++--- lib/browser/user.js | 5 +- lib/email-password-auth-methods.js | 12 +++-- package-lock.json | 6 +-- src/js_app.hpp | 16 +++--- src/js_email_password_auth.hpp | 32 +++++++++-- src/js_user.hpp | 25 ++++++--- src/rpc.cpp | 2 +- tests/js/app-tests.js | 14 ++--- tests/js/session-tests.js | 12 ++--- tests/js/user-tests.js | 85 +++++++++++++++--------------- types/index.d.ts | 12 +++++ 13 files changed, 165 insertions(+), 96 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3928c5f6e0..eaa50d5377 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ NOTE: Support for syncing with realm.cloud.io and/or Realm Object Server has bee NOTE: This version bumps the Realm file format to version 11. It is not possible to downgrade to earlier versions. Older files will automatically be upgraded to the new file format. Files created by Realm JavaScript prior to v1.0.0, might not be upgradeable. Only [Realm Studio 10.0.0](https://github.com/realm/realm-studio/releases/tag/v10.0.0-beta.1) or later will be able to open the new file format. ### Breaking changes +* `Realm.Auth.EmailPassword.registerEmail()` has been renamed to `Realm.Auth.EmailPassword.registerUser()`. +* `Realm.User.identity` has been renamed to `Realm.User.id`. +* `Realm.User.token` has been renamed to `Realm.User.accessToken`. +* Change instance methods `Realm.App.currentUser()` and `Realm.App.allUsers()` to instance properties `Realm.App.currentUser` and `Realm.App.allUsers`. * `Realm.Auth.UserAPIKeyProvider` has been replaced by `Realm.Auth.ApiKeyProvider`. * `user.auth.apiKeys` has been replaced by `user.apiKeys`. * The instance methods on the ApiKeyAuth instance (`user.apiKeys`) have gotten their APIKey(s) suffix removed: Ex. `apiKeys.createAPIKey` has been replaced by `apiKeys.create`. @@ -12,7 +16,7 @@ NOTE: This version bumps the Realm file format to version 11. It is not possible * `app.auth.emailPassword` has been replaced by `user.emailPasswordAuth`. ### Enhancements -* None. +* Added RemoteMongoClient functionality to `Realm.User` ### Fixed * Failed to parse arguments correctly, causing the error `callback must be of type 'function', got (undefined)` when calling `Realm.App.emailPassword.sendResetPasswordEmail()` and `Realm.App.emailPassword.resendConfirmationEmail()`. ([#3037](https://github.com/realm/realm-js/issues/3037), since v10.0.0-beta.1) diff --git a/docs/sync.js b/docs/sync.js index cb9b9b510a..0adab6a7f7 100644 --- a/docs/sync.js +++ b/docs/sync.js @@ -107,14 +107,14 @@ * * @returns {Realm.User} The current user, `null` is no current user. */ - currentUser() { } + get currentUser() { } /** * Returns a dictionary of alll users. Users' identity is used as key. * * @returns {Array} */ - allUsers() { } + get allUsers() { } /** * Switches the current user. @@ -139,7 +139,7 @@ * { * // Creating a new user, by registering via email & password * const app = new Realm.App(config); - * await app.emailPasswordAuth.registerEmail('john@example.com', 'some-secure-password'); + * await app.emailPasswordAuth.registerUser('john@example.com', 'some-secure-password'); * } * * @type {Realm.Auth.EmailPasswordAuth} @@ -366,17 +366,17 @@ class Auth { class EmailPasswordAuth { /** - * Registers a new email identity with the username/password provider, + * Registers a new email identity with the email/password provider, * and sends a confirmation email to the provided address. * * @param {string} email - The email address of the user to register. * @param {string} password - The password that the user created for the new username/password identity. * @returns {Promise} */ - registerEmail(email, password) { } + registerUser(email, password) { } /** - * Confirms an email identity with the username/password provider. + * Confirms an email identity with the email/password provider. * * @param {string} token - The confirmation token that was emailed to the user. * @param {string} id - The confirmation token id that was emailed to the user. @@ -408,6 +408,17 @@ class EmailPasswordAuth { * @returns {Promise} */ resetPassword(password, token, id) { } + + /** + * Resets the password of an email identity using the + * password reset function set up in the application. + * + * @param {string} email - The email address of the user. + * @param {string} password - The desired new password. + * @param {Array} args - A bson array of arguments. + * @return {Promose} + */ + callResetPasswordFunction(email, password, args) { } } /** @@ -477,14 +488,21 @@ class User { * The identity is a guaranteed to be unique among all users on MongoDB Realm Cloud . * @type {string} */ - get identity() { } + get id() { } + + /** + * Gets this user's access token. This is the user's credential for accessing the MongoDB + * Realm Cloud and should be treated as sensitive data. + * @type {string} + */ + get accessToken() { } /** * Gets this user's refresh token. This is the user's credential for accessing the MongoDB * Realm Cloud and should be treated as sensitive data. * @type {string} */ - get token() { } + get refreshToken() { } /** * Gets this user's associated custom data. This is application-specific data provided by the server. diff --git a/lib/browser/user.js b/lib/browser/user.js index eceb1895ed..d6c26fa6a0 100644 --- a/lib/browser/user.js +++ b/lib/browser/user.js @@ -36,8 +36,9 @@ createMethods(User.prototype, objectTypes.USER, [ ]); Object.defineProperties(User.prototype, { - identity: { get: getterForProperty('identity') }, - token: { get: getterForProperty('token') }, + id: { get: getterForProperty('id') }, + accessToken: { get: getterForProperty('accessToken') }, + refreshToken: { get: getterForProperty('refreshToken') }, profile: { get: getterForProperty('profile') }, isLoggedIn: { get: getterForProperty('isLoggedIn') }, state: { get: getterForProperty('state') }, diff --git a/lib/email-password-auth-methods.js b/lib/email-password-auth-methods.js index bd297d6b71..a93cdfe1c7 100644 --- a/lib/email-password-auth-methods.js +++ b/lib/email-password-auth-methods.js @@ -20,8 +20,8 @@ const {promisify} = require("./utils.js"); const instanceMethods = { - registerEmail(email, password) { - return promisify(cb => this._registerEmail(email, password, cb)); + registerUser(email, password) { + return promisify(cb => this._registerUser(email, password, cb)); }, confirmUser(token, token_id) { @@ -37,8 +37,12 @@ const instanceMethods = { }, resetPassword(password, token, token_id) { - return promisify(cb => this._sendResetPasswordEmail(password, token_id, token_id, cb)); - } + return promisify(cb => this._resetPassword(password, token, token_id)); + }, + + callResetPasswordFunction(email, password, bsonArgs) { + return promisify(cb => this._callResetPasswordFunction(email, password, bsonArgs)); + }, }; const staticMethods = { diff --git a/package-lock.json b/package-lock.json index 39badfffde..42671b7fb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2169,7 +2169,7 @@ "babylon": { "version": "7.0.0-beta.44", "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.44.tgz", - "integrity": "sha512-5Hlm13BJVAioCHpImtFqNOF2H3ieTOHd0fmFGMxOJ9jgeFqeAwsv3u5P5cR7CSeFrkgHsT19DgFJkHV0/Mcd8g==", + "integrity": "sha1-iRWeFebjDFCW4i1zjYwK+KDoyh0=", "dev": true }, "balanced-match": { @@ -4142,7 +4142,7 @@ "esrecurse": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", "dev": true, "requires": { "estraverse": "^4.1.0" @@ -9612,7 +9612,7 @@ "which": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", "dev": true, "requires": { "isexe": "^2.0.0" diff --git a/src/js_app.hpp b/src/js_app.hpp index e0ef666d5f..16fb920eaf 100644 --- a/src/js_app.hpp +++ b/src/js_app.hpp @@ -61,22 +61,22 @@ class AppClass : public ClassDefinition { static void get_app_id(ContextType, ObjectType, ReturnValue &); static void get_email_password_auth(ContextType, ObjectType, ReturnValue &); + static void get_current_user(ContextType, ObjectType, ReturnValue &); + static void get_all_users(ContextType, ObjectType, ReturnValue &); PropertyMap const properties = { {"id", {wrap, nullptr}}, {"emailPasswordAuth", {wrap, nullptr}}, + {"currentUser", {wrap, nullptr}}, + {"allUsers", {wrap, nullptr}} }; static void login(ContextType, ObjectType, Arguments&, ReturnValue&); - static void all_users(ContextType, ObjectType, Arguments&, ReturnValue&); - static void current_user(ContextType, ObjectType, Arguments&, ReturnValue&); static void switch_user(ContextType, ObjectType, Arguments&, ReturnValue&); static void remove_user(ContextType, ObjectType, Arguments&, ReturnValue&); MethodMap const methods = { {"_login", wrap}, - {"allUsers", wrap}, - {"currentUser", wrap}, {"switchUser", wrap}, {"_removeUser", wrap}, }; @@ -222,9 +222,7 @@ void AppClass::login(ContextType ctx, ObjectType this_object, Arguments &args } template -void AppClass::all_users(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { - args.validate_count(0); - +void AppClass::get_all_users(ContextType ctx, ObjectType this_object, ReturnValue& return_value) { auto app = *get_internal>(ctx, this_object); auto users = Object::create_empty(ctx); @@ -236,9 +234,7 @@ void AppClass::all_users(ContextType ctx, ObjectType this_object, Arguments& } template -void AppClass::current_user(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { - args.validate_count(0); - +void AppClass::get_current_user(ContextType ctx, ObjectType this_object, ReturnValue& return_value) { auto app = *get_internal>(ctx, this_object); auto user = app->current_user(); if (user) { diff --git a/src/js_email_password_auth.hpp b/src/js_email_password_auth.hpp index 09ab7a303e..1172a6c578 100644 --- a/src/js_email_password_auth.hpp +++ b/src/js_email_password_auth.hpp @@ -49,18 +49,21 @@ class EmailPasswordAuthClass : public ClassDefinition const properties = { }; - static void register_email(ContextType, ObjectType, Arguments&, ReturnValue&); + static void register_user(ContextType, ObjectType, Arguments&, ReturnValue&); static void confirm_user(ContextType, ObjectType, Arguments&, ReturnValue&); static void resend_confirmation_email(ContextType, ObjectType, Arguments&, ReturnValue&); static void send_reset_password_email(ContextType, ObjectType, Arguments&, ReturnValue&); static void reset_password(ContextType, ObjectType, Arguments&, ReturnValue&); + static void call_reset_password_function(ContextType, ObjectType, Arguments&, ReturnValue&); MethodMap const methods = { - {"_registerEmail", wrap}, + {"_registerUser", wrap}, {"_confirmUser", wrap}, {"_resendConfirmationEmail", wrap}, {"_sendResetPasswordEmail", wrap}, - {"_resetPassword", wrap} + {"_resetPassword", wrap}, + {"_callResetPasswordFunction", wrap}, + }; }; @@ -76,7 +79,7 @@ typename T::Object EmailPasswordAuthClass::create_instance(ContextType ctx, S } template -void EmailPasswordAuthClass::register_email(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { +void EmailPasswordAuthClass::register_user(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { args.validate_count(3); auto& client = *get_internal>(ctx, this_object); @@ -139,5 +142,26 @@ void EmailPasswordAuthClass::reset_password(ContextType ctx, ObjectType this_ client.reset_password(password, token, token_id, make_callback_handler(ctx, this_object, callback)); } +template +void EmailPasswordAuthClass::call_reset_password_function(ContextType ctx, ObjectType this_object, Arguments& args, ReturnValue& return_value) { + args.validate_count(4); + + auto& client = *get_internal>(ctx, this_object); + + auto email = Value::validated_to_string(ctx, args[0], "email"); + auto password = Value::validated_to_string(ctx, args[1], "password"); + auto call_args_js = Value::validated_to_array(ctx, args[1], "args"); + auto callback = Value::validated_to_function(ctx, args[3], "callback"); + + bson::BsonArray call_args_bson; + uint32_t length = Object::validated_get_length(ctx, call_args_js); + for (uint32_t index = 0; index < length; ++index) { + auto obj = Object::get_property(ctx, call_args_js, index); + call_args_bson.push_back(Value::to_bson(ctx, obj)); + } + + client.call_reset_password_function(email, password, call_args_bson, make_callback_handler(ctx, this_object, callback)); +} + } } diff --git a/src/js_user.hpp b/src/js_user.hpp index 0002a21035..1bbe8dd4ea 100644 --- a/src/js_user.hpp +++ b/src/js_user.hpp @@ -70,8 +70,9 @@ class UserClass : public ClassDefinition> { static FunctionType create_constructor(ContextType); static ObjectType create_instance(ContextType, SharedUser, SharedApp); - static void get_identity(ContextType, ObjectType, ReturnValue &); - static void get_token(ContextType, ObjectType, ReturnValue &); + static void get_id(ContextType, ObjectType, ReturnValue &); + static void get_access_token(ContextType, ObjectType, ReturnValue &); + static void get_refresh_token(ContextType, ObjectType, ReturnValue &); static void get_profile(ContextType, ObjectType, ReturnValue &); static void is_logged_in(ContextType, ObjectType, ReturnValue &); static void get_state(ContextType, ObjectType, ReturnValue &); @@ -79,8 +80,9 @@ class UserClass : public ClassDefinition> { static void get_api_keys(ContextType, ObjectType, ReturnValue &); PropertyMap const properties = { - {"identity", {wrap, nullptr}}, - {"token", {wrap, nullptr}}, + {"id", {wrap, nullptr}}, + {"accessToken", {wrap, nullptr}}, + {"refreshToken", {wrap, nullptr}}, {"profile", {wrap, nullptr}}, {"isLoggedIn", {wrap, nullptr}}, {"state", {wrap, nullptr}}, @@ -123,17 +125,24 @@ typename T::Object UserClass::create_instance(ContextType ctx, SharedUser use } template -void UserClass::get_identity(ContextType ctx, ObjectType object, ReturnValue &return_value) { - std::string identity = get_internal>(ctx, object)->get()->identity(); - return_value.set(identity); +void UserClass::get_id(ContextType ctx, ObjectType object, ReturnValue &return_value) { + std::string id = get_internal>(ctx, object)->get()->identity(); + return_value.set(id); } template -void UserClass::get_token(ContextType ctx, ObjectType object, ReturnValue &return_value) { +void UserClass::get_access_token(ContextType ctx, ObjectType object, ReturnValue &return_value) { + std::string token = get_internal>(ctx, object)->get()->access_token(); + return_value.set(token); +} + +template +void UserClass::get_refresh_token(ContextType ctx, ObjectType object, ReturnValue &return_value) { std::string token = get_internal>(ctx, object)->get()->refresh_token(); return_value.set(token); } + template void UserClass::is_logged_in(ContextType ctx, ObjectType object, ReturnValue &return_value) { auto logged_in = get_internal>(ctx, object)->get()->is_logged_in(); diff --git a/src/rpc.cpp b/src/rpc.cpp index 3c01019a57..29cda179ae 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -754,7 +754,7 @@ json RPCServer::serialize_json_value(JSValueRef js_value) { else if (jsc::Object::is_instance>(m_context, js_object)) { auto user = jsc::Object::get_internal>(m_context, js_object); json user_dict { - {"identity", user->get()->identity()}, + {"id", user->get()->identity()}, }; return { {"type", RealmObjectTypesUser}, diff --git a/tests/js/app-tests.js b/tests/js/app-tests.js index 0ecebce33c..f7787fdcf2 100644 --- a/tests/js/app-tests.js +++ b/tests/js/app-tests.js @@ -123,30 +123,30 @@ module.exports = { async testLogoutAndAllUsers() { let app = new Realm.App(config); let credentials = Realm.Credentials.anonymous(); - let users = app.allUsers(); + let users = app.allUsers; const nUsers = Object.keys(users).length; let user = await app.logIn(credentials); - users = app.allUsers(); + users = app.allUsers; TestCase.assertEqual(Object.keys(users).length, nUsers + 1) await user.logOut(); - users = app.allUsers(); + users = app.allUsers; TestCase.assertEqual(Object.keys(users).length, nUsers); }, async testCurrentUser() { let app = new Realm.App(config); - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); let credentials = Realm.Credentials.anonymous(); let user1 = await app.logIn(credentials); - let user2 = app.currentUser(); - TestCase.assertEqual(user1.identity, user2.identity); + let user2 = app.currentUser; + TestCase.assertEqual(user1.id, user2.id); await user1.logOut(); - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); }, async testMongoDBRealmSync() { diff --git a/tests/js/session-tests.js b/tests/js/session-tests.js index 5febcbdd2a..8b98adc39a 100644 --- a/tests/js/session-tests.js +++ b/tests/js/session-tests.js @@ -168,9 +168,9 @@ module.exports = { const session = realm.syncSession; TestCase.assertInstanceOf(session, Realm.Sync.Session); - TestCase.assertEqual(session.user.identity, user.identity); + TestCase.assertEqual(session.user.id, user.id); TestCase.assertEqual(session.config.url, config.sync.url); - TestCase.assertEqual(session.config.user.identity, config.sync.user.identity); + TestCase.assertEqual(session.config.user.id, config.sync.user.id); TestCase.assertEqual(session.state, 'active'); return user.logOut(); }); @@ -208,9 +208,9 @@ module.exports = { const session = realm.syncSession; TestCase.assertInstanceOf(session, Realm.Sync.Session); - TestCase.assertEqual(session.user.identity, user.identity); + TestCase.assertEqual(session.user.id, user.id); TestCase.assertEqual(session.config.url, config.sync.url); - TestCase.assertEqual(session.config.user.identity, config.sync.user.identity); + TestCase.assertEqual(session.config.user.id, config.sync.user.id); TestCase.assertEqual(session.state, 'active'); realm.close() }); @@ -482,11 +482,11 @@ module.exports = { realm1.close(); // delete Realm on server - let encodedPath = encodeURIComponent(`${user.identity}/myrealm`); + let encodedPath = encodeURIComponent(`${user.id}/myrealm`); let url = new URL(`/realms/files/${encodedPath}`, user.server); let options = { headers: { - Authorization: `${user.token}`, + Authorization: `${user.accessToken}`, 'Content-Type': 'application/json', }, method: 'DELETE', diff --git a/tests/js/user-tests.js b/tests/js/user-tests.js index bdf07c53e5..2771e495bf 100644 --- a/tests/js/user-tests.js +++ b/tests/js/user-tests.js @@ -42,16 +42,17 @@ if (isNodeProcess) { function assertIsUser(user) { TestCase.assertDefined(user); TestCase.assertType(user, 'object'); - TestCase.assertType(user.token, 'string'); - TestCase.assertType(user.identity, 'string'); + TestCase.assertType(user.accessToken, 'string'); + TestCase.assertType(user.refreshToken, 'string'); + TestCase.assertType(user.id, 'string'); TestCase.assertType(user.customData, 'object'); TestCase.assertInstanceOf(user, Realm.User); } function assertIsSameUser(value, user) { assertIsUser(value); - TestCase.assertEqual(value.token, user.token); - TestCase.assertEqual(value.identity, user.identity); + TestCase.assertEqual(value.accessToken, user.accessToken); + TestCase.assertEqual(value.id, user.id); } function assertIsError(error, message) { @@ -91,21 +92,21 @@ function randomNonVerifiableEmail() { async function registerAndLogInEmailUser(app) { const validEmail = randomVerifiableEmail(); const validPassword = "test1234567890"; - await app.emailPasswordAuth.registerEmail(validEmail, validPassword); + await app.emailPasswordAuth.registerUser(validEmail, validPassword); let user = await app.logIn(Realm.Credentials.emailPassword(validEmail, validPassword)) assertIsUser(user); - assertIsSameUser(user, app.currentUser()); + assertIsSameUser(user, app.currentUser); return user; } async function logOutExistingUsers(app) { - let users = app.allUsers(); - Object.keys(app.allUsers()).forEach(async id => await users[id].logOut()); + let users = app.allUsers; + Object.keys(app.allUsers).forEach(async id => await users[id].logOut()); } module.exports = { - // tests also logIn() and currentUser() + // tests also logIn() and currentUser async testLogout() { let app = new Realm.App(appConfig); await logOutExistingUsers(app); @@ -113,10 +114,10 @@ module.exports = { let user = await app.logIn(credentials); assertIsUser(user); - assertIsSameUser(user, app.currentUser()); + assertIsSameUser(user, app.currentUser); await user.logOut(); // Is now logged out. - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); }, testEmailPasswordMissingUsername() { @@ -157,7 +158,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(invalidEmail, invalidPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerEmail(invalidEmail, invalidPassword)); + err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerUser(invalidEmail, invalidPassword)); TestCase.assertEqual(err.message, "password must be between 6 and 128 characters"); err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user did not register @@ -166,7 +167,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(invalidEmail, validPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerEmail(invalidEmail, validPassword)); + err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerUser(invalidEmail, validPassword)); TestCase.assertEqual(err.message, `failed to confirm user ${invalidEmail}`); err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user did not register @@ -175,7 +176,7 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(validEmail, invalidPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerEmail(validEmail, invalidPassword)); + err = await TestCase.assertThrowsAsync(async() => app.emailPasswordAuth.registerUser(validEmail, invalidPassword)); TestCase.assertEqual(err.message, "password must be between 6 and 128 characters"); err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user did not register @@ -184,10 +185,10 @@ module.exports = { let credentials = Realm.Credentials.emailPassword(validEmail, validPassword); let err = await TestCase.assertThrowsAsync(async() => app.logIn(credentials)); TestCase.assertEqual(err.message, "invalid username/password"); // this user does not exist yet - await app.emailPasswordAuth.registerEmail(validEmail, validPassword); + await app.emailPasswordAuth.registerUser(validEmail, validPassword); let user = await app.logIn(credentials) assertIsUser(user); - assertIsSameUser(user, app.currentUser()); + assertIsSameUser(user, app.currentUser); await user.logOut(); } }, @@ -262,41 +263,41 @@ module.exports = { let app = new Realm.App(appConfig); await logOutExistingUsers(app); - let all = app.allUsers(); + let all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 0, "Noone to begin with"); let credentials = Realm.Credentials.anonymous(); let user1 = await app.logIn(credentials); - all = app.allUsers(); + all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 1, "One user"); - assertIsSameUser(all[user1.identity], user1); + assertIsSameUser(all[user1.id], user1); let user2 = await app.logIn(Realm.Credentials.anonymous()); - all = app.allUsers(); + all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 1, "still one user"); // NOTE: the list of users is in latest-first order. - assertIsSameUser(all[user2.identity], user2); - assertIsSameUser(all[user1.identity], user1); + assertIsSameUser(all[user2.id], user2); + assertIsSameUser(all[user1.id], user1); await user2.logOut(); // logs out the shared anonymous session - all = app.allUsers(); + all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 0, "All gone"); }, async testCurrentWithAnonymous() { let app = new Realm.App(appConfig); await logOutExistingUsers(app); - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); let firstUser = await app.logIn(Realm.Credentials.anonymous()); - assertIsSameUser(app.currentUser(), firstUser); + assertIsSameUser(app.currentUser, firstUser); let secondUser = await app.logIn(Realm.Credentials.anonymous()); // the most recently logged in user is considered current TestCase.assertTrue(firstUser.isLoggedIn); TestCase.assertTrue(secondUser.isLoggedIn); - assertIsSameUser(app.currentUser(), secondUser); + assertIsSameUser(app.currentUser, secondUser); secondUser.logOut(); // since anonymous user sessions are shared, firstUser is logged out as well - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); TestCase.assertFalse(firstUser.isLoggedIn); TestCase.assertFalse(secondUser.isLoggedIn); }, @@ -304,47 +305,47 @@ module.exports = { async testCurrentWithEmail() { let app = new Realm.App(appConfig); await logOutExistingUsers(app); - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); let firstUser = await registerAndLogInEmailUser(app); - assertIsSameUser(app.currentUser(), firstUser); + assertIsSameUser(app.currentUser, firstUser); let secondUser = await registerAndLogInEmailUser(app); - assertIsSameUser(app.currentUser(), secondUser); // the most recently logged in user is considered current + assertIsSameUser(app.currentUser, secondUser); // the most recently logged in user is considered current await secondUser.logOut(); - assertIsSameUser(app.currentUser(), firstUser); // auto change back to another logged in user + assertIsSameUser(app.currentUser, firstUser); // auto change back to another logged in user await firstUser.logOut(); - TestCase.assertNull(app.currentUser()); + TestCase.assertNull(app.currentUser); }, async testAllWithEmail() { let app = new Realm.App(appConfig); await logOutExistingUsers(app); - let all = app.allUsers(); + let all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 0, "Noone to begin with"); let credentials = Realm.Credentials.anonymous(); let user1 = await registerAndLogInEmailUser(app); - all = app.allUsers(); + all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 1, "One user"); - assertIsSameUser(all[user1.identity], user1); + assertIsSameUser(all[user1.id], user1); let user2 = await registerAndLogInEmailUser(app); - all = app.allUsers(); + all = app.allUsers; TestCase.assertArrayLength(Object.keys(all), 2, "Two users"); // NOTE: the list of users is in latest-first order. - assertIsSameUser(all[user2.identity], user2); - assertIsSameUser(all[user1.identity], user1); + assertIsSameUser(all[user2.id], user2); + assertIsSameUser(all[user1.id], user1); await user2.logOut(); - all = app.allUsers(); - assertIsSameUser(all[user2.identity], user2); - assertIsSameUser(all[user1.identity], user1); + all = app.allUsers; + assertIsSameUser(all[user2.id], user2); + assertIsSameUser(all[user1.id], user1); TestCase.assertFalse(user2.isLoggedIn); TestCase.assertTrue(user1.isLoggedIn); TestCase.assertArrayLength(Object.keys(all), 2, "still holds references to both users"); await user1.logOut(); - all = app.allUsers(); + all = app.allUsers; TestCase.assertFalse(user1.isLoggedIn); TestCase.assertFalse(user2.isLoggedIn); TestCase.assertArrayLength(Object.keys(all), 2, "still holds references to both users"); // FIXME: is this actually expected? diff --git a/types/index.d.ts b/types/index.d.ts index d0357d4dbe..92d71b29bc 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -329,6 +329,18 @@ declare namespace Realm { readonly prototype: Results; }; + interface UserProfile { + name?: string; + email?: string; + pictureUrl?: string; + firstName?: string; + lastName?: string; + gender?: string; + birthday?: string; + minAge?: string; + maxAge?: string; + } + interface UserMap { [identity: string]: User } From 4ff57ac9a0b6ebdc4642da7d400f85817882e08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kr=C3=A6n=20Hansen?= Date: Fri, 10 Jul 2020 15:15:35 +0200 Subject: [PATCH 30/30] Removed UserProfile from index.d.ts and updated pictureUrl --- types/app.d.ts | 2 +- types/index.d.ts | 12 ------------ 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/types/app.d.ts b/types/app.d.ts index be2eb9b4ee..108d1027c9 100644 --- a/types/app.d.ts +++ b/types/app.d.ts @@ -335,7 +335,7 @@ declare namespace Realm { /** * A URL referencing a picture associated with the user. */ - pictureURL?: string; + pictureUrl?: string; /** * The users first name. diff --git a/types/index.d.ts b/types/index.d.ts index 92d71b29bc..d0357d4dbe 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -329,18 +329,6 @@ declare namespace Realm { readonly prototype: Results; }; - interface UserProfile { - name?: string; - email?: string; - pictureUrl?: string; - firstName?: string; - lastName?: string; - gender?: string; - birthday?: string; - minAge?: string; - maxAge?: string; - } - interface UserMap { [identity: string]: User }