From 493a83e8731368fe0ad20076a15a5c35f0d9a703 Mon Sep 17 00:00:00 2001 From: Kenneth Geisshirt Date: Fri, 29 Sep 2023 15:59:26 +0200 Subject: [PATCH] Override fetch for Altas App Services --- CHANGELOG.md | 2 +- .../tests/src/hooks/import-app-before.ts | 1 + .../tests/src/node/custom-fetch.ts | 66 +++++++++++++++++++ integration-tests/tests/src/node/index.ts | 1 + packages/realm/realm-constants.json | 2 +- packages/realm/src/app-services/App.ts | 15 ++++- packages/realm/src/platform/network.ts | 2 +- 7 files changed, 85 insertions(+), 4 deletions(-) create mode 100644 integration-tests/tests/src/node/custom-fetch.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index c1655f64c59..1ecae47bf4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ * None ### Enhancements -* None +* Expose `Realm.App.Configuration.fetchOverride` to enable implementing a custom [`fetch`](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) function. ([#6159](https://github.com/realm/realm-js/issues/6159)) ### Fixed * ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?) diff --git a/integration-tests/tests/src/hooks/import-app-before.ts b/integration-tests/tests/src/hooks/import-app-before.ts index 8dd6c38c981..4178f522186 100644 --- a/integration-tests/tests/src/hooks/import-app-before.ts +++ b/integration-tests/tests/src/hooks/import-app-before.ts @@ -32,6 +32,7 @@ export type AppConfigurationRelaxed = { timeout?: number; multiplexSessions?: boolean; baseFilePath?: string; + fetchOverride?: any; }; export function importAppBefore(config: AppConfig | { config: AppConfig }, sdkConfig?: AppConfigurationRelaxed): void { diff --git a/integration-tests/tests/src/node/custom-fetch.ts b/integration-tests/tests/src/node/custom-fetch.ts new file mode 100644 index 00000000000..a36b77ec5b3 --- /dev/null +++ b/integration-tests/tests/src/node/custom-fetch.ts @@ -0,0 +1,66 @@ +//////////////////////////////////////////////////////////////////////////// +// +// Copyright 2022 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 { importAppBefore } from "../hooks"; +import { buildAppConfig } from "../utils/build-app-config"; +import fetch, { Request } from "node-fetch"; +import Realm from "realm"; + +describe("custom fetch", () => { + let called = false; + + const HTTP_METHOD: Record = { + [0]: "GET", + [1]: "POST", + [2]: "PUT", + [3]: "PATCH", + [4]: "DELETE", + }; + + const customFetch = async (request: Request) => { + called = true; + const { url, body, ...rest } = request; + if (typeof request.method == "number") { + rest.method = HTTP_METHOD[request.method]; + } + const response = await fetch(url, rest); + return response; + }; + + importAppBefore(buildAppConfig("with-anon").anonAuth(), { fetchOverride: customFetch }); + afterEach(() => { + Realm.clearTestState(); + }); + + it("custom fetch is called", async function (this: Mocha.Context & AppContext & RealmContext) { + let user; + called = false; + try { + expect(this.app).instanceOf(Realm.App); + const credentials = Realm.Credentials.anonymous(); + user = await this.app.logIn(credentials); + expect(called).equals(true); + expect(user).instanceOf(Realm.User); + expect(user.deviceId).to.not.be.null; + expect(user.providerType).equals("anon-user"); + } finally { + await user?.logOut(); + } + }); +}); diff --git a/integration-tests/tests/src/node/index.ts b/integration-tests/tests/src/node/index.ts index bb3850d4497..9d1de838a12 100644 --- a/integration-tests/tests/src/node/index.ts +++ b/integration-tests/tests/src/node/index.ts @@ -20,5 +20,6 @@ import "./analytics"; import "./clean-exit"; +import "./custom-fetch"; import "./path"; import "./sync-proxy"; diff --git a/packages/realm/realm-constants.json b/packages/realm/realm-constants.json index c842d7e8777..12b6c14f300 100644 --- a/packages/realm/realm-constants.json +++ b/packages/realm/realm-constants.json @@ -1 +1 @@ -{"REALM_ANONYMIZED_BUNDLE_ID":"tkgif/+3l1e9wStGJp2TOngAK3UcQ2u7OM8ZYJU5JYo="} \ No newline at end of file +{"REALM_ANONYMIZED_BUNDLE_ID":"1RmJBlqbKuzyRiPm4AsdIIxe8xlRUntGcGFEwUnUh6A="} \ No newline at end of file diff --git a/packages/realm/src/app-services/App.ts b/packages/realm/src/app-services/App.ts index cb8684d16dd..99b18fec234 100644 --- a/packages/realm/src/app-services/App.ts +++ b/packages/realm/src/app-services/App.ts @@ -16,6 +16,7 @@ // //////////////////////////////////////////////////////////////////////////// +import { inject } from "src/platform/network"; import { AnyUser, Credentials, @@ -30,6 +31,7 @@ import { createNetworkTransport, deviceInfo, fs, + network, } from "../internal"; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -140,6 +142,12 @@ export type AppConfiguration = { * @since 12.2.0 */ metadata?: Metadata; + + /** + * Specify a custom `fetch` implementation. + * @since 12.3.0 + */ + fetchOverride?: any; }; /** @@ -261,7 +269,8 @@ export class App< constructor(configOrId: AppConfiguration | string) { const config: AppConfiguration = typeof configOrId === "string" ? { id: configOrId } : configOrId; assert.object(config, "config"); - const { id, baseUrl, app, timeout, multiplexSessions = true, baseFilePath, metadata } = config; + const { id, baseUrl, app, timeout, multiplexSessions = true, baseFilePath, metadata, fetchOverride } = config; + assert.string(id, "id"); if (timeout !== undefined) { assert.number(timeout, "timeout"); @@ -277,6 +286,10 @@ export class App< } } + if (fetchOverride) { + inject({ fetch: fetchOverride }); + } + fs.ensureDirectoryForFile(fs.joinPaths(baseFilePath || fs.getDefaultDirectoryPath(), "mongodb-realm")); // TODO: This used getSharedApp in the legacy SDK, but it's failing AppTests this.internal = binding.App.getUncachedApp( diff --git a/packages/realm/src/platform/network.ts b/packages/realm/src/platform/network.ts index 1cf7969c814..b1d93434fc4 100644 --- a/packages/realm/src/platform/network.ts +++ b/packages/realm/src/platform/network.ts @@ -60,5 +60,5 @@ export const network: NetworkType = { }; export function inject(injected: NetworkType) { - Object.freeze(Object.assign(network, injected)); + Object.assign(network, injected); }