Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RJS-2732: Support updating the App's base URL via experimental export #6518

Merged
merged 22 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* None

### Enhancements
* None
* Experimental feature: The new instance members `App.baseUrl` and `App.updateBaseUrl()` allow for retrieving and updating the base URL currently used for requests sent to Atlas App Services. These APIs are only available after importing `"realm/experimental/base-url"`. ([#6518](/~https://github.com/realm/realm-js/pull/6518))

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](/~https://github.com/realm/realm-js/issues/????), since v?.?.?)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@ PODS:
- React-Core
- React-jsi
- ReactTestApp-Resources (1.0.0-dev)
- RealmJS (12.7.0-rc.0):
- RealmJS (12.7.1):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder why this was not already on main 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably just didn't get committed 🤷‍♀️

- React
- RNFS (2.20.0):
- React-Core
Expand Down Expand Up @@ -1356,7 +1356,7 @@ SPEC CHECKSUMS:
ReactNativeHost: 446b46cbfc2d16420bfd249e9064802e929fa9b7
ReactTestApp-DevSupport: 5cd1b02b4d146811d29dc2455a249f0743fda504
ReactTestApp-Resources: d200e68756fa45c648f369210bd7ee0c14759f5a
RealmJS: 0c85b5fd6406447f4526d7b73d0a8025cd8b342a
RealmJS: 3fdc3b6cb6d4ff67eaf0e5f7f861be51304e7525
RNFS: 4ac0f0ea233904cb798630b3c077808c06931688
SocketRocket: f32cd54efbe0f095c4d7594881e52619cfe80b17
Yoga: 805bf71192903b20fc14babe48080582fee65a80
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
////////////////////////////////////////////////////////////////////////////

const { makeMetroConfig } = require("@rnx-kit/metro-config");

module.exports = makeMetroConfig({
transformer: {
getTransformOptions: async () => ({
Expand Down
15 changes: 5 additions & 10 deletions integration-tests/tests/src/hooks/import-app-before.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
//
////////////////////////////////////////////////////////////////////////////

import Realm from "realm";
import Realm, { AppConfiguration } from "realm";

import { AppConfig, AppImporter, Credentials } from "@realm/app-importer";
import { mongodbServiceType } from "../utils/ExtendedAppConfigBuilder";
Expand All @@ -39,14 +39,6 @@ export { baseUrl };

const allowSkippingServerTests = typeof environment.baseUrl === "undefined" && missingServer !== false;

export type AppConfigurationRelaxed = {
id?: string;
baseUrl?: string;
timeout?: number;
multiplexSessions?: boolean;
baseFilePath?: string;
};

const credentials: Credentials =
typeof publicKey === "string" && typeof privateKey === "string"
? {
Expand Down Expand Up @@ -94,7 +86,10 @@ function ensureSkippedAppImportAfterHook() {
* If the `missingServer` context is set the suite will be skipped.
* If the import fails due to a connection refusal, the suite will be skipped and a warning printed at the end of the test run.
*/
export function importAppBefore(config: AppConfig | { config: AppConfig }, sdkConfig?: AppConfigurationRelaxed): void {
export function importAppBefore(
config: AppConfig | { config: AppConfig },
sdkConfig?: Partial<AppConfiguration>,
): void {
// Unwrap when passed a builder directly
if ("config" in config) {
return importAppBefore(config.config, sdkConfig);
Expand Down
2 changes: 2 additions & 0 deletions integration-tests/tests/src/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import "./tests/credentials/email-password";
import "./tests/credentials/function";
import "./tests/credentials/jwt";

import "./tests/experimental/base-url";

import "./tests/sync/app";
import "./tests/sync/asymmetric";
import "./tests/sync/client-reset";
Expand Down
55 changes: 55 additions & 0 deletions integration-tests/tests/src/tests/experimental/base-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2024 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.
//
////////////////////////////////////////////////////////////////////////////

import { expect } from "chai";
import "realm/experimental/base-url";

import { baseUrl as originalBaseUrl, importAppBefore } from "../../hooks";
import { buildAppConfig } from "../../utils/build-app-config";

describe.skipIf(environment.missingServer, "Base URL", () => {
importAppBefore(buildAppConfig("with-anon").anonAuth());

it("returns the base URL used", function (this: AppContext) {
expect(this.app.baseUrl).equals(originalBaseUrl);
});

// TODO: Should implement when I've got a working fetch mock.
it.skip("updates the URL", async function (this: AppContext) {
// TODO
});
Comment on lines +33 to +35
Copy link
Contributor Author

@elle-j elle-j Apr 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will add this using a fetch mock.


it.skip("resets to default URL", async function (this: AppContext) {
// TODO
});

it("throws when assigning via setter", function (this: AppContext) {
// @ts-expect-error Assigning to read-only property.
expect(() => (this.app.baseUrl = "new URL")).to.throw("Cannot assign the base URL, please use 'updateBaseUrl()'");

expect(this.app.baseUrl).equals(originalBaseUrl);
});

it("rejects when updating to invalid URL", async function (this: AppContext) {
await expect(this.app.updateBaseUrl("https://invalid")).to.be.rejectedWith(
"request to https://invalid/api/client/",
);

expect(this.app.baseUrl).equals(originalBaseUrl);
});
});
2 changes: 1 addition & 1 deletion integration-tests/tests/tsconfig.common.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"composite": true,
"target": "es2022",
"module": "es2022",
"moduleResolution": "node",
"moduleResolution": "Bundler",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you check this works with npm test --workspace @realm/integration-tests (where we use raw Mocha and tsx to transpile TypeScript)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works ✅

"useDefineForClassFields": false,
"strict": true,
"strictFunctionTypes": false,
Expand Down
2 changes: 1 addition & 1 deletion integration-tests/tests/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
{ "path": "./tsconfig.common.json" },
{ "path": "./tsconfig.node.json" }
]
}
}
2 changes: 2 additions & 0 deletions packages/realm/bindgen/js_opt_in_spec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -485,6 +485,8 @@ classes:
- unsubscribe
- call_function
- make_streaming_request
- update_base_url
- get_base_url

WatchStream:
methods:
Expand Down
29 changes: 29 additions & 0 deletions packages/realm/experimental/base-url.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2024 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.
//
////////////////////////////////////////////////////////////////////////////

// Our use of `exports` in `packages/realm/package.json` is not enabled by
// default when using Metro and RN. In these cases, modules imported from
// "realm/experimental" will search for the file in the same path, rather
// than what is pointed to under `exports`. Thus, we use this .js file to
// in turn import the necessary module.

// (Enabling `unstable_enablePackageExports` in the metro config unexpectedly
// does not work.)

/* eslint-env commonjs */
module.exports = require("../dist/experimental/base-url");
4 changes: 4 additions & 0 deletions packages/realm/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
"node": "./dist/platform/node/index.js",
"react-native": "./index.react-native.js"
},
"./experimental/base-url": {
"types": "./dist/public-types/experimental/base-url.d.ts",
"default": "./dist/experimental/base-url.js"
},
"./scripts/submit-analytics": "./scripts/submit-analytics.mjs",
"./react-native.config.js": "./react-native.config.js",
"./package.json": "./package.json"
Expand Down
57 changes: 57 additions & 0 deletions packages/realm/src/experimental/base-url.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
////////////////////////////////////////////////////////////////////////////
//
// Copyright 2024 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.
//
////////////////////////////////////////////////////////////////////////////

import { App } from "../app-services/App";

declare module "../app-services/App" {
interface App {
/**
* Get the current base URL used for sending requests to Atlas App Services.
*
* If an {@link App.updateBaseUrl | updateBaseUrl} operation is currently in
* progress, this value will not be updated with the new value until that
* operation has completed.
* @experimental This feature is experimental and may be changed or removed.
*/
get baseUrl(): string;

/**
* Update the base URL used for sending requests to Atlas App Services. If this is
* set to an empty string or `null`, it will reset the base URL to the default one.
*
* If this operation fails, the app will continue to use the original base URL.
* If another {@link App} operation is started while this function is in progress,
* that request will use the original base URL location information.
* @experimental This feature is experimental and may be changed or removed.
*/
updateBaseUrl(newUrl: string | null): Promise<void>;
}
}

Object.defineProperty(App.prototype, "baseUrl", {
get(this: App) {
return this.internal.getBaseUrl();
},
set() {
throw new Error("Cannot assign the base URL, please use 'updateBaseUrl()'.");
},
});

App.prototype.updateBaseUrl = function (this: App, newUrl: string | null) {
return this.internal.updateBaseUrl(newUrl ?? undefined);
};
Loading