Skip to content

Commit 59a9b58

Browse files
committed
Added React Native persistence class
1 parent 7a11397 commit 59a9b58

File tree

8 files changed

+209
-5
lines changed

8 files changed

+209
-5
lines changed

packages-exp/auth-compat-exp/index.rn.ts

+4
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@
2323
*/
2424

2525
import { testFxn } from './src';
26+
import { AsyncStorage } from 'react-native';
27+
import { ReactNativePersistence } from '@firebase/auth-exp/src/core/persistence/react';
28+
29+
const reactNativeLocalPersistence = new ReactNativePersistence(AsyncStorage);
2630

2731
testFxn();

packages-exp/auth-compat-exp/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@
2626
},
2727
"peerDependencies": {
2828
"@firebase/app-exp": "0.x",
29-
"@firebase/app-types-exp": "0.x"
29+
"@firebase/app-types-exp": "0.x",
30+
"@firebase/auth-exp": "0.x",
31+
"@firebase/auth-types-exp": "0.x"
3032
},
3133
"dependencies": {
3234
"tslib": "1.11.1"
3335
},
3436
"license": "Apache-2.0",
3537
"devDependencies": {
38+
"react-native": "0.62.2",
3639
"rollup": "1.32.1",
3740
"rollup-plugin-json": "4.0.0",
3841
"rollup-plugin-replace": "2.2.0",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/**
19+
* Basic stub for what is expected from the package 'react-native'.
20+
*
21+
* This should be a subset `@types/react-native` which cannot be installed
22+
* because it has conflicting definitions with typescript/dom. If included in
23+
* deps, yarn will attempt to install this in the root directory of the
24+
* monolithic repository which will then be included in the base `tsconfig.json`
25+
* via `typeroots` and then break every other package in this repo.
26+
*/
27+
28+
declare module 'react-native' {
29+
interface ReactNativeAsyncStorage {
30+
setItem: (key: string, value: string) => Promise<void>
31+
getItem: (key: string) => Promise<string|null>
32+
removeItem: (key: string) => Promise<void>
33+
}
34+
export const AsyncStorage: ReactNativeAsyncStorage;
35+
}

packages-exp/auth-compat-exp/rollup.config.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ const es5Builds = [
5555
external: id => deps.some(dep => id === dep || id.startsWith(`${dep}/`))
5656
},
5757
/**
58-
* App React Native Builds
58+
* React Native Builds
5959
*/
6060
{
6161
input: 'index.rn.ts',

packages-exp/auth-exp/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
},
2727
"peerDependencies": {
2828
"@firebase/app-exp": "0.x",
29-
"@firebase/app-types-exp": "0.x"
29+
"@firebase/app-types-exp": "0.x",
30+
"@firebase/auth-types-exp": "0.x"
3031
},
3132
"dependencies": {
3233
"@firebase/util": "^0.2.44",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { expect } from 'chai';
19+
import * as sinon from 'sinon';
20+
21+
import { testUser } from '../../../test/mock_auth';
22+
import {PersistedBlob, PersistenceType} from './';
23+
import {ReactNativePersistence} from './react';
24+
import {inMemoryPersistence} from './in_memory';
25+
import {ReactNativeAsyncStorage} from '@firebase/auth-types-exp';
26+
27+
/**
28+
* Wraps in-memory storage with the react native AsyncStorage API.
29+
*/
30+
class FakeAsyncStorage implements ReactNativeAsyncStorage {
31+
private readonly delegate = inMemoryPersistence;
32+
33+
getItem(key: string): Promise<string | null> {
34+
return this.delegate.get(key);
35+
}
36+
removeItem(key: string): Promise<void> {
37+
return this.delegate.remove(key);
38+
}
39+
setItem(key: string, value: string): Promise<void> {
40+
return this.delegate.set(key, value);
41+
}
42+
}
43+
44+
describe('core/persistence/react', () => {
45+
const persistence = new ReactNativePersistence(new FakeAsyncStorage());
46+
47+
beforeEach(() => {
48+
localStorage.clear();
49+
sessionStorage.clear();
50+
});
51+
52+
afterEach(() => sinon.restore());
53+
54+
describe('ReactNativePersistence', () => {
55+
56+
it('should work with persistence type', async () => {
57+
const key = 'my-super-special-persistence-type';
58+
const value = PersistenceType.LOCAL;
59+
expect(await persistence.get(key)).to.be.null;
60+
await persistence.set(key, value);
61+
expect(await persistence.get(key)).to.be.eq(value);
62+
expect(await persistence.get('other-key')).to.be.null;
63+
await persistence.remove(key);
64+
expect(await persistence.get(key)).to.be.null;
65+
});
66+
67+
it('should return persistedblob from user', async () => {
68+
const key = 'my-super-special-user';
69+
const value = testUser('some-uid');
70+
71+
expect(await persistence.get(key)).to.be.null;
72+
await persistence.set(key, value.toPlainObject());
73+
const out = await persistence.get<PersistedBlob>(key);
74+
expect(out!['uid']).to.eql(value.uid);
75+
await persistence.remove(key);
76+
expect(await persistence.get(key)).to.be.null;
77+
});
78+
79+
describe('#isAvailable', () => {
80+
it('should emit false if localStorage setItem throws', async () => {
81+
sinon.stub(localStorage, 'setItem').throws(new Error('nope'));
82+
expect(await persistence.isAvailable()).to.be.false;
83+
});
84+
85+
it('should emit false if localStorage removeItem throws', async () => {
86+
sinon.stub(localStorage, 'removeItem').throws(new Error('nope'));
87+
expect(await persistence.isAvailable()).to.be.false;
88+
});
89+
90+
it('should emit true if everything works properly', async () => {
91+
expect(await persistence.isAvailable()).to.be.true;
92+
});
93+
});
94+
});
95+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import {
19+
Persistence,
20+
PersistenceType,
21+
PersistenceValue,
22+
STORAGE_AVAILABLE_KEY
23+
} from './';
24+
import {ReactNativeAsyncStorage} from '@firebase/auth-types-exp';
25+
26+
/**
27+
* Persistence class that wraps AsyncStorage imported from `react-native` or `@react-native-community/async-storage`.
28+
*/
29+
export class ReactNativePersistence implements Persistence {
30+
readonly type: PersistenceType = PersistenceType.LOCAL;
31+
private readonly storage: ReactNativeAsyncStorage;
32+
33+
constructor(storage: ReactNativeAsyncStorage) {
34+
this.storage = storage;
35+
}
36+
37+
async isAvailable(): Promise<boolean> {
38+
try {
39+
if (!this.storage) {
40+
return false;
41+
}
42+
await this.storage.setItem(STORAGE_AVAILABLE_KEY, '1');
43+
await this.storage.removeItem(STORAGE_AVAILABLE_KEY);
44+
return true;
45+
} catch {
46+
return false;
47+
}
48+
}
49+
50+
async set(key: string, value: PersistenceValue): Promise<void> {
51+
await this.storage.setItem(key, JSON.stringify(value));
52+
}
53+
54+
async get<T extends PersistenceValue>(
55+
key: string
56+
): Promise<T | null> {
57+
const json = await this.storage.getItem(key);
58+
return json ? JSON.parse(json) : null;
59+
}
60+
61+
async remove(key: string): Promise<void> {
62+
await this.storage.removeItem(key);
63+
}
64+
}

packages-exp/auth-types-exp/index.d.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18-
export interface TestType {
19-
prop?: string;
18+
export interface ReactNativeAsyncStorage {
19+
setItem: (key: string, value: string) => Promise<void>
20+
getItem: (key: string) => Promise<string|null>
21+
removeItem: (key: string) => Promise<void>
2022
}

0 commit comments

Comments
 (0)