diff --git a/packages/firebase/src/index.rn.ts b/packages/firebase/src/index.rn.ts index b1e4c6dc083..c6e3c6f11bc 100644 --- a/packages/firebase/src/index.rn.ts +++ b/packages/firebase/src/index.rn.ts @@ -20,7 +20,10 @@ import { name, version } from '../package.json'; import '../auth'; import '../database'; +// TODO(b/158625454): Storage doesn't actually work by default in RN (it uses +// `atob`). We should provide a RN build that works out of the box. import '../storage'; +import '../firestore'; firebase.registerVersion(name, version, 'rn'); diff --git a/packages/firestore/index.node.memory.ts b/packages/firestore/index.node.memory.ts index d491d2a8dc1..1cfd55f8977 100644 --- a/packages/firestore/index.node.memory.ts +++ b/packages/firestore/index.node.memory.ts @@ -35,7 +35,7 @@ export function registerFirestore(instance: FirebaseNamespace): void { instance, (app, auth) => new Firestore(app, auth, new MemoryComponentProvider()) ); - instance.registerVersion(name, version); + instance.registerVersion(name, version, 'node'); } registerFirestore(firebase); diff --git a/packages/firestore/index.rn.memory.ts b/packages/firestore/index.rn.memory.ts new file mode 100644 index 00000000000..803e7be3c73 --- /dev/null +++ b/packages/firestore/index.rn.memory.ts @@ -0,0 +1,42 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * 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 firebase from '@firebase/app'; +import { FirebaseNamespace } from '@firebase/app-types'; + +import { Firestore } from './src/api/database'; +import { MemoryComponentProvider } from './src/core/component_provider'; +import { configureForFirebase } from './src/platform/config'; + +import './register-module'; +import './src/platform_rn/rn_init'; + +import { name, version } from './package.json'; + +/** + * Registers the memory-only Firestore build for ReactNative with the components + * framework. + */ +export function registerFirestore(instance: FirebaseNamespace): void { + configureForFirebase( + instance, + (app, auth) => new Firestore(app, auth, new MemoryComponentProvider()) + ); + instance.registerVersion(name, version, 'rn'); +} + +registerFirestore(firebase); diff --git a/packages/firestore/index.rn.ts b/packages/firestore/index.rn.ts new file mode 100644 index 00000000000..3130be10374 --- /dev/null +++ b/packages/firestore/index.rn.ts @@ -0,0 +1,41 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * 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 firebase from '@firebase/app'; +import { FirebaseNamespace } from '@firebase/app-types'; + +import { Firestore } from './src/api/database'; +import { IndexedDbComponentProvider } from './src/core/component_provider'; +import { configureForFirebase } from './src/platform/config'; + +import './register-module'; +import './src/platform_rn/rn_init'; + +import { name, version } from './package.json'; + +/** + * Registers the main Firestore ReactNative build with the components framework. + * Persistence can be enabled via `firebase.firestore().enablePersistence()`. + */ +export function registerFirestore(instance: FirebaseNamespace): void { + configureForFirebase( + instance, + (app, auth) => new Firestore(app, auth, new IndexedDbComponentProvider()) + ); + instance.registerVersion(name, version, 'rn'); +} + +registerFirestore(firebase); diff --git a/packages/firestore/memory/package.json b/packages/firestore/memory/package.json index ac0df500a26..04a27eb839a 100644 --- a/packages/firestore/memory/package.json +++ b/packages/firestore/memory/package.json @@ -3,6 +3,7 @@ "description": "A memory-only build of the Cloud Firestore JS SDK.", "main": "../dist/index.memory.node.cjs.js", "main-esm2017": "../dist/index.memory.node.esm2017.js", + "react-native": "../dist/index.memory.rn.esm2017.js", "browser": "../dist/index.memory.cjs.js", "module": "../dist/index.memory.esm.js", "esm2017": "../dist/index.memory.esm2017.js", diff --git a/packages/firestore/package.json b/packages/firestore/package.json index ba3e332455b..7018bf88ba4 100644 --- a/packages/firestore/package.json +++ b/packages/firestore/package.json @@ -41,6 +41,7 @@ }, "main": "dist/index.node.cjs.js", "main-esm2017": "dist/index.node.esm2017.js", + "react-native": "dist/index.rn.esm2017.js", "browser": "dist/index.cjs.js", "module": "dist/index.esm.js", "esm2017": "dist/index.esm2017.js", diff --git a/packages/firestore/rollup.config.es2017.js b/packages/firestore/rollup.config.es2017.js index fcabdabe0b1..9ef6e4fd326 100644 --- a/packages/firestore/rollup.config.es2017.js +++ b/packages/firestore/rollup.config.es2017.js @@ -100,6 +100,31 @@ const browserBuilds = [ } ]; +const reactNativeBuilds = [ + // Persistence build + { + input: 'index.rn.ts', + output: { + file: pkg['react-native'], + format: 'es', + sourcemap: true + }, + plugins: browserBuildPlugins, + external: resolveBrowserExterns + }, + // Memory-only build + { + input: 'index.rn.memory.ts', + output: { + file: path.resolve('./memory', memoryPkg['react-native']), + format: 'es', + sourcemap: true + }, + plugins: browserBuildPlugins, + external: resolveBrowserExterns + } +]; + // MARK: Node builds const nodeBuildPlugins = [ @@ -145,4 +170,4 @@ const nodeBuilds = [ } ]; -export default [...browserBuilds, ...nodeBuilds]; +export default [...browserBuilds, ...reactNativeBuilds, ...nodeBuilds]; diff --git a/packages/firestore/src/platform_browser/browser_platform.ts b/packages/firestore/src/platform_browser/browser_platform.ts index 38133db4df5..70a2dc9655c 100644 --- a/packages/firestore/src/platform_browser/browser_platform.ts +++ b/packages/firestore/src/platform_browser/browser_platform.ts @@ -19,7 +19,7 @@ import { DatabaseId, DatabaseInfo } from '../core/database_info'; import { Platform } from '../platform/platform'; import { Connection } from '../remote/connection'; import { JsonProtoSerializer } from '../remote/serializer'; -import { ConnectivityMonitor } from './../remote/connectivity_monitor'; +import { ConnectivityMonitor } from '../remote/connectivity_monitor'; import { NoopConnectivityMonitor } from '../remote/connectivity_monitor_noop'; import { BrowserConnectivityMonitor } from './browser_connectivity_monitor'; @@ -27,13 +27,10 @@ import { WebChannelConnection } from './webchannel_connection'; import { debugAssert } from '../util/assert'; // Implements the Platform API for browsers and some browser-like environments -// (including ReactNative). +// (including ReactNative, which has its own ReactNativePlatform that extends +// from this class). export class BrowserPlatform implements Platform { - readonly base64Available: boolean; - - constructor() { - this.base64Available = typeof atob !== 'undefined'; - } + readonly base64Available = typeof atob !== 'undefined'; get document(): Document | null { // `document` is not always available, e.g. in ReactNative and WebWorkers. diff --git a/packages/firestore/src/platform_rn/rn_init.ts b/packages/firestore/src/platform_rn/rn_init.ts new file mode 100644 index 00000000000..442a86d079c --- /dev/null +++ b/packages/firestore/src/platform_rn/rn_init.ts @@ -0,0 +1,28 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * 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 { PlatformSupport } from '../platform/platform'; +import { ReactNativePlatform } from './rn_platform'; + +/** + * This code needs to run before Firestore is used. This can be achieved in + * several ways: + * 1) Through the JSCompiler compiling this code and then (automatically) + * executing it before exporting the Firestore symbols. + * 2) Through importing this module first in a Firestore main module + */ +PlatformSupport.setPlatform(new ReactNativePlatform()); diff --git a/packages/firestore/src/platform_rn/rn_platform.ts b/packages/firestore/src/platform_rn/rn_platform.ts new file mode 100644 index 00000000000..2ce9d9bfbd9 --- /dev/null +++ b/packages/firestore/src/platform_rn/rn_platform.ts @@ -0,0 +1,36 @@ +/** + * @license + * Copyright 2020 Google LLC + * + * 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 { BrowserPlatform } from '../platform_browser/browser_platform'; +import { base64 } from '@firebase/util'; + +// Implements the Platform API for ReactNative. +export class ReactNativePlatform extends BrowserPlatform { + readonly base64Available = true; + + atob(encoded: string): string { + // WebSafe uses a different URL-encoding safe alphabet that doesn't match + // the encoding used on the backend. + return base64.decodeString(encoded, /* webSafe =*/ false); + } + + btoa(raw: string): string { + // WebSafe uses a different URL-encoding safe alphabet that doesn't match + // the encoding used on the backend. + return base64.encodeString(raw, /* webSafe =*/ false); + } +}