Merge branch 'master' of https://github.com/invertase/react-native-firebase into firestore-transactions
This commit is contained in:
commit
8e00b7e607
54
.eslintrc
54
.eslintrc
|
@ -1,46 +1,36 @@
|
|||
{
|
||||
"extends": "airbnb",
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"prettier",
|
||||
"prettier/flowtype",
|
||||
"prettier/react"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"plugins": [
|
||||
"flowtype"
|
||||
"flowtype",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"es6": true,
|
||||
"jasmine": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"prettier/prettier": ["error", {
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true
|
||||
}],
|
||||
|
||||
"react/forbid-prop-types": "warn",
|
||||
"react/jsx-filename-extension": [
|
||||
"off", { "extensions": [".js", ".jsx"] }
|
||||
],
|
||||
|
||||
"class-methods-use-this": 0,
|
||||
"no-plusplus": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-return-assign": 0,
|
||||
"no-undef": 0,
|
||||
"no-use-before-define": 0,
|
||||
"arrow-body-style": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"radix": 0,
|
||||
"new-cap": 0,
|
||||
"max-len": 0,
|
||||
"no-continue": 0,
|
||||
"no-console": 0,
|
||||
"global-require": 0,
|
||||
"import/extensions": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"react/jsx-filename-extension": 0,
|
||||
"no-unused-expressions": 0,
|
||||
"flowtype/no-unused-expressions": ['error', {
|
||||
allowShortCircuit: false,
|
||||
allowTernary: false,
|
||||
allowTaggedTemplates: false,
|
||||
}]
|
||||
"no-plusplus": 0,
|
||||
"no-undef": 0,
|
||||
"no-underscore-dangle": "off",
|
||||
"no-use-before-define": 0
|
||||
},
|
||||
"globals": {
|
||||
"__DEV__": true,
|
||||
|
|
32
.flowconfig
32
.flowconfig
|
@ -3,7 +3,7 @@
|
|||
.*/*[.]android.js
|
||||
|
||||
; Ignore "BUCK" generated dirs
|
||||
.*/node_modules/react-native/\.buckd/
|
||||
<PROJECT_ROOT>/\.buckd/
|
||||
|
||||
; Ignore unexpected extra "@providesModule"
|
||||
.*/node_modules/.*/node_modules/fbjs/.*
|
||||
|
@ -16,22 +16,8 @@
|
|||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
# React Native problems
|
||||
.*/node_modules/metro-bundler/src/DeltaBundler/DeltaCalculator.js.flow
|
||||
.*/node_modules/metro-bundler/src/DeltaBundler/DeltaPatcher.js.flow
|
||||
.*/node_modules/metro-bundler/src/node-haste/AssetResolutionCache.js.flow
|
||||
.*/node_modules/metro-bundler/src/node-haste/DependencyGraph.js.flow
|
||||
#.*/node_modules/react-native/Libraries/Animated/src/nodes/AnimatedStyle.js
|
||||
#.*/node_modules/react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader.js
|
||||
#.*/node_modules/react-native/Libraries/Experimental/SwipeableRow/SwipeableFlatList.js
|
||||
#.*/node_modules/react-native/Libraries/Experimental/SwipeableRow/SwipeableListView.js
|
||||
#.*/node_modules/react-native/Libraries/Image/ImageBackground.js
|
||||
#.*/node_modules/react-native/Libraries/Lists/FlatList.js
|
||||
#.*/node_modules/react-native/Libraries/Lists/MetroListView.js
|
||||
#.*/node_modules/react-native/Libraries/Lists/SectionList.js
|
||||
#.*/node_modules/react-native/Libraries/Lists/ViewabilityHelper.js
|
||||
#.*/node_modules/react-native/Libraries/Lists/VirtualizedList.js
|
||||
#.*/node_modules/react-native/Libraries/Lists/VirtualizedSectionList.js
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
# Ignore dist folder
|
||||
.*/dist/.*
|
||||
|
@ -44,12 +30,13 @@
|
|||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow/
|
||||
node_modules/react-native/flow-github/
|
||||
|
||||
[options]
|
||||
module.system=haste
|
||||
|
||||
emoji=true
|
||||
|
||||
module.system=haste
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
@ -63,10 +50,9 @@ suppress_type=$FlowIssue
|
|||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
suppress_type=$FixMe
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(5[0-6]\\|[1-4][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowBug.*
|
||||
|
@ -74,4 +60,4 @@ suppress_comment=\\(.\\|\n\\)*\\$FlowBug.*
|
|||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
[version]
|
||||
^0.56.0
|
||||
^0.61.0
|
||||
|
|
|
@ -5,7 +5,7 @@ The issue list of this repo is exclusively for bug reports.
|
|||
|
||||
1) For feature requests, please use our Canny board: https://react-native-firebase.canny.io/feature-requests
|
||||
|
||||
2) For questions and support please use our Discord chat: https://discord.gg/t6bdqMs or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase
|
||||
2) For questions and support please use our Discord chat: https://discord.gg/C9aK28N or Stack Overflow: https://stackoverflow.com/questions/tagged/react-native-firebase
|
||||
|
||||
3) If this is a setup issue then please make sure you've correctly followed the setup guides, most setup issues such as 'duplicate dex files', 'default app has not been initialized' etc are all down to an incorrect setup as the guides haven't been correctly followed.
|
||||
-->
|
||||
|
@ -14,26 +14,30 @@ The issue list of this repo is exclusively for bug reports.
|
|||
|
||||
<!--- Please write your issue here, provide as much detail as you can, code snippets, key files which will help us to debug such as your `Podfile` and/or `app/build.gradle` file). -->
|
||||
|
||||
|
||||
|
||||
### Environment
|
||||
|
||||
<!--- (e.g. iOS, Android, Both) --->
|
||||
|
||||
1. Application Target Platform:
|
||||
|
||||
<!--- (e.g. macOS Sierra, Windows 10) --->
|
||||
|
||||
2. Development Operating System:
|
||||
|
||||
<!--- (Xcode or Android Studio version, iOS or Android SDK version - if relevant) --->
|
||||
|
||||
3. Build Tools:
|
||||
|
||||
<!--- (e.g. 0.45.1) --->
|
||||
|
||||
4. React Native version:
|
||||
|
||||
<!--- (e.g. 2.1.3) --->
|
||||
|
||||
5. RNFirebase Version:
|
||||
|
||||
<!--- (e.g. database, auth, messaging, analytics etc - or N/A if not applicable) --->
|
||||
|
||||
6. Firebase Module:
|
||||
|
||||
<!-- Love react-native-firebase? Please consider supporting our collective:
|
||||
|
|
|
@ -10,6 +10,7 @@ npm-debug.log
|
|||
*.perspectivev3
|
||||
*.xcuserstate
|
||||
project.xcworkspace/
|
||||
atlassian-ide-plugin
|
||||
xcuserdata/
|
||||
|
||||
# Example
|
||||
|
@ -78,3 +79,4 @@ local.properties
|
|||
**/ios/Pods/**
|
||||
**/ios/ReactNativeFirebaseDemo.xcworkspace/
|
||||
dist
|
||||
version.js
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at oss@invertase.io. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
|
@ -5,15 +5,16 @@
|
|||
First, thank you for considering contributing to react-native-firebase! It's people like you that make the open source community such a great community! 😊
|
||||
|
||||
We welcome any type of contribution, not only code. You can help with
|
||||
- **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
|
||||
- **Marketing**: writing blog posts, howto's, printing stickers, ...
|
||||
- **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
|
||||
- **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
|
||||
- **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-firebase).
|
||||
|
||||
* **QA**: file bug reports, the more details you can give the better (e.g. screenshots with the console open)
|
||||
* **Marketing**: writing blog posts, howto's, printing stickers, ...
|
||||
* **Community**: presenting the project at meetups, organizing a dedicated meetup for the local community, ...
|
||||
* **Code**: take a look at the [open issues](issues). Even if you can't write code, commenting on them, showing that you care about a given issue matters. It helps us triage them.
|
||||
* **Money**: we welcome financial contributions in full transparency on our [open collective](https://opencollective.com/react-native-firebase).
|
||||
|
||||
## Your First Contribution
|
||||
|
||||
Working on your first Pull Request? You can learn how from this *free* series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
||||
Working on your first Pull Request? You can learn how from this _free_ series, [How to Contribute to an Open Source Project on GitHub](https://egghead.io/series/how-to-contribute-to-an-open-source-project-on-github).
|
||||
|
||||
## Submitting code
|
||||
|
||||
|
@ -41,14 +42,12 @@ You can also reach us at oss@invertase.io
|
|||
Thank you to all the people who have already contributed to react-native-firebase!
|
||||
<a href="graphs/contributors"><img src="https://opencollective.com/react-native-firebase/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
### Backers
|
||||
|
||||
Thank you to all our backers! [[Become a backer](https://opencollective.com/react-native-firebase#backer)]
|
||||
|
||||
<a href="https://opencollective.com/react-native-firebase#backers" target="_blank"><img src="https://opencollective.com/react-native-firebase/backers.svg?width=890"></a>
|
||||
|
||||
|
||||
### Sponsors
|
||||
|
||||
Thank you to all our sponsors! (please ask your company to also support this open source project by [becoming a sponsor](https://opencollective.com/react-native-firebase#sponsor))
|
||||
|
|
27
README.md
27
README.md
|
@ -11,7 +11,7 @@
|
|||
<a href="/LICENSE"><img src="https://img.shields.io/npm/l/react-native-firebase.svg?style=flat-square" alt="License"></a>
|
||||
<a href="#backers"><img src="https://opencollective.com/react-native-firebase/backers/badge.svg" alt="Backers on Open Collective"></a>
|
||||
<a href="#sponsors"><img src="https://opencollective.com/react-native-firebase/sponsors/badge.svg" alt="Sponsors on Open Collective"></a>
|
||||
<a href="https://discord.gg/t6bdqMs"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square" alt="Chat"></a>
|
||||
<a href="https://discord.gg/C9aK28N"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?style=flat-square" alt="Chat"></a>
|
||||
<a href="https://twitter.com/rnfirebase"><img src="https://img.shields.io/twitter/follow/rnfirebase.svg?style=social&label=Follow" alt="Follow on Twitter"></a>
|
||||
</p>
|
||||
|
||||
|
@ -30,40 +30,41 @@ All in all, RNFirebase provides much faster performance (~2x) over the web SDK a
|
|||
---
|
||||
|
||||
## Supported Firebase Features
|
||||
> The Web SDK column indicates what modules/functionality from the Web SDK are usable within React Native.
|
||||
|
||||
> The Web SDK column indicates what modules/functionality from the Web SDK are usable within React Native.
|
||||
|
||||
> '**?**' indicates partial support
|
||||
|
||||
| Firebase Features | v1.x.x | v2.x.x | v3.x.x | v3.1.x | v3.2.x | Web SDK |
|
||||
| ---------------------- | :---: | :---: | :---: | :---: | :---: | :---: |
|
||||
| -------------------------- | :----: | :----: | :----: | :----: | :----: | :-----: |
|
||||
| **AdMob** | ❌ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Analytics** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **App Indexing** | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ |
|
||||
| **Authentication** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| _-- Phone Auth_ | ❌ | ❌ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Core** | ❌ |**?**| ✅ | ✅ | ✅ | ✅ |
|
||||
| **Core** | ❌ | **?** | ✅ | ✅ | ✅ | ✅ |
|
||||
| _-- Multiple Apps_ | ❌ | ❌ | ✅ | ✅ | ✅ | ✅ |
|
||||
| **Cloud Firestore** | ❌ | ❌ | ✅ | ✅ | ✅ |**?**|
|
||||
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ | ✅ | ✅ |**?**|
|
||||
| **Cloud Firestore** | ❌ | ❌ | ✅ | ✅ | ✅ | **?** |
|
||||
| **Cloud Messaging (FCM)** | ✅ | ✅ | ✅ | ✅ | ✅ | **?** |
|
||||
| **Crashlytics** | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ |
|
||||
| **Crash Reporting** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Dynamic Links** | ❌ | ❌ | ❌ | ✅ | ✅ | ❌ |
|
||||
| **Invites** | ❌ | ❌ | ❌ |**?**|**?**| ❌ |
|
||||
| **Invites** | ❌ | ❌ | ❌ | **?** | **?** | ❌ |
|
||||
| **Performance Monitoring** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Realtime Database** | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| _-- Offline Persistence_ | ✅ | ✅ | ✅ | ✅ | ✅ |**?**|
|
||||
| _-- Offline Persistence_ | ✅ | ✅ | ✅ | ✅ | ✅ | **?** |
|
||||
| _-- Transactions_ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
|
||||
| **Remote Config** | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
|
||||
| **Storage** | ✅ | ✅ | ✅ | ✅ | ✅ |**?**|
|
||||
| **Storage** | ✅ | ✅ | ✅ | ✅ | ✅ | **?** |
|
||||
|
||||
---
|
||||
|
||||
### Supported versions - React Native / Firebase
|
||||
|
||||
> The table below shows the supported versions of React Native and the Firebase SDKs for different versions of `react-native-firebase`
|
||||
|
||||
| | 1.X.X | 2.0.X | 2.1.X / 2.2.X | 3.0.X | 3.1.X | 3.2.X |
|
||||
|------------------------|-------------|-------------|-----------------|----------|-------------|----------|
|
||||
| -------------------- | ----------- | ----------- | ------------- | -------- | ----------- | -------- |
|
||||
| React Native | 0.36 - 0.39 | 0.40 - 0.46 | 0.47 + | 0.48 + | 0.48 - 0.49 | 0.50 + |
|
||||
| Firebase Android SDK | 10.2.0 + | 11.0.0 + | 11.0.0 + | 11.4.2 + | 11.6.0 + | 11.6.2 + |
|
||||
| Firebase iOS SDK | 3.15.0 + | 4.0.0 + | 4.0.0 + | 4.3.0 + | 4.5.0 + | 4.7.0 + |
|
||||
|
@ -76,7 +77,7 @@ To check out our latest docs, visit [rnfirebase.io](https://rnfirebase.io)
|
|||
|
||||
## Questions
|
||||
|
||||
For questions and support please use our [Discord chat](https://discord.gg/t6bdqMs) or [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native-firebase). The issue list of this repo is **exclusively** for bug reports.
|
||||
For questions and support please use our [Discord chat](https://discord.gg/C9aK28N) or [Stack Overflow](https://stackoverflow.com/questions/tagged/react-native-firebase). The issue list of this repo is **exclusively** for bug reports.
|
||||
|
||||
## Issues
|
||||
|
||||
|
@ -96,7 +97,7 @@ Detailed changes for each release are documented in the [releases notes](https:/
|
|||
|
||||
RNFirebase is an Apache-2.0 licensed open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [sponsors](#sponsors) and [backers](#backers). If you'd like to join them, please consider:
|
||||
|
||||
- [Become a backer or sponsor on Open Collective](https://opencollective.com/react-native-firebase).
|
||||
* [Become a backer or sponsor on Open Collective](https://opencollective.com/react-native-firebase).
|
||||
|
||||
### Sponsors
|
||||
|
||||
|
@ -131,4 +132,4 @@ Thank you to all the people who have already contributed to RNFirebase!
|
|||
|
||||
## License
|
||||
|
||||
- See [LICENSE](/LICENSE)
|
||||
* See [LICENSE](/LICENSE)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
buildscript {
|
||||
ext.firebaseVersion = '11.4.2'
|
||||
ext.firebaseVersion = '11.8.0'
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
|
|
|
@ -6,6 +6,7 @@ import android.util.Log;
|
|||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
@ -35,7 +36,9 @@ import com.google.firebase.auth.AuthCredential;
|
|||
import com.google.firebase.auth.AuthResult;
|
||||
import com.google.firebase.auth.FirebaseAuthInvalidCredentialsException;
|
||||
import com.google.firebase.auth.FirebaseAuthProvider;
|
||||
import com.google.firebase.auth.FirebaseUserMetadata;
|
||||
import com.google.firebase.auth.GithubAuthProvider;
|
||||
import com.google.firebase.auth.OAuthProvider;
|
||||
import com.google.firebase.auth.PhoneAuthCredential;
|
||||
import com.google.firebase.auth.PhoneAuthProvider;
|
||||
import com.google.firebase.auth.ProviderQueryResult;
|
||||
|
@ -91,13 +94,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
FirebaseUser user = firebaseAuth.getCurrentUser();
|
||||
WritableMap msgMap = Arguments.createMap();
|
||||
if (user != null) {
|
||||
msgMap.putBoolean("authenticated", true);
|
||||
msgMap.putString("appName", appName); // for js side distribution
|
||||
msgMap.putMap("user", firebaseUserToMap(user));
|
||||
Utils.sendEvent(mReactContext, "auth_state_changed", msgMap);
|
||||
} else {
|
||||
msgMap.putString("appName", appName); // for js side distribution
|
||||
msgMap.putBoolean("authenticated", false);
|
||||
Utils.sendEvent(mReactContext, "auth_state_changed", msgMap);
|
||||
}
|
||||
}
|
||||
|
@ -178,11 +179,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* signOut
|
||||
*
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void signOut(String appName, Promise promise) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
|
@ -197,13 +193,17 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* signInAnonymously
|
||||
*
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void signInAnonymously(String appName, final Promise promise) {
|
||||
signInAnonymously(appName, promise, false);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void signInAnonymouslyAndRetrieveData(String appName, final Promise promise) {
|
||||
signInAnonymously(appName, promise, true);
|
||||
}
|
||||
|
||||
public void signInAnonymously(String appName, final Promise promise, final boolean withData) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
|
@ -213,8 +213,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
@Override
|
||||
public void onSuccess(AuthResult authResult) {
|
||||
Log.d(TAG, "signInAnonymously:onComplete:success");
|
||||
if (withData) {
|
||||
promiseWithAuthResult(authResult, promise);
|
||||
} else {
|
||||
promiseWithUser(authResult.getUser(), promise);
|
||||
}
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(new OnFailureListener() {
|
||||
@Override
|
||||
|
@ -234,6 +238,15 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
*/
|
||||
@ReactMethod
|
||||
public void createUserWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) {
|
||||
createUserWithEmailAndPassword(appName, email, password, promise, false);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void createUserAndRetrieveDataWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) {
|
||||
createUserWithEmailAndPassword(appName, email, password, promise, true);
|
||||
}
|
||||
|
||||
public void createUserWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) {
|
||||
Log.d(TAG, "createUserWithEmailAndPassword");
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
@ -243,8 +256,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
@Override
|
||||
public void onSuccess(AuthResult authResult) {
|
||||
Log.d(TAG, "createUserWithEmailAndPassword:onComplete:success");
|
||||
if (withData) {
|
||||
promiseWithAuthResult(authResult, promise);
|
||||
} else {
|
||||
promiseWithUser(authResult.getUser(), promise);
|
||||
}
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(new OnFailureListener() {
|
||||
@Override
|
||||
|
@ -264,6 +281,15 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
*/
|
||||
@ReactMethod
|
||||
public void signInWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) {
|
||||
signInWithEmailAndPassword(appName, email, password, promise, false);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void signInAndRetrieveDataWithEmailAndPassword(String appName, final String email, final String password, final Promise promise) {
|
||||
signInWithEmailAndPassword(appName, email, password, promise, true);
|
||||
}
|
||||
|
||||
public void signInWithEmailAndPassword(String appName, final String email, final String password, final Promise promise, final boolean withData) {
|
||||
Log.d(TAG, "signInWithEmailAndPassword");
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
@ -273,8 +299,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
@Override
|
||||
public void onSuccess(AuthResult authResult) {
|
||||
Log.d(TAG, "signInWithEmailAndPassword:onComplete:success");
|
||||
if (withData) {
|
||||
promiseWithAuthResult(authResult, promise);
|
||||
} else {
|
||||
promiseWithUser(authResult.getUser(), promise);
|
||||
}
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(new OnFailureListener() {
|
||||
@Override
|
||||
|
@ -286,14 +316,18 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* signInWithCustomToken
|
||||
*
|
||||
* @param token
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void signInWithCustomToken(String appName, final String token, final Promise promise) {
|
||||
signInWithCustomToken(appName, token, promise, false);
|
||||
}
|
||||
|
||||
|
||||
@ReactMethod
|
||||
public void signInAndRetrieveDataWithCustomToken(String appName, final String token, final Promise promise) {
|
||||
signInWithCustomToken(appName, token, promise, true);
|
||||
}
|
||||
|
||||
public void signInWithCustomToken(String appName, final String token, final Promise promise, final boolean withData) {
|
||||
Log.d(TAG, "signInWithCustomToken");
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
@ -303,8 +337,12 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
@Override
|
||||
public void onSuccess(AuthResult authResult) {
|
||||
Log.d(TAG, "signInWithCustomToken:onComplete:success");
|
||||
if (withData) {
|
||||
promiseWithAuthResult(authResult, promise);
|
||||
} else {
|
||||
promiseWithUser(authResult.getUser(), promise);
|
||||
}
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(new OnFailureListener() {
|
||||
@Override
|
||||
|
@ -350,26 +388,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getCurrentUser - returns the current user, probably no need for this due to
|
||||
* js side already listening for user auth changes
|
||||
*
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void getCurrentUser(String appName, final Promise promise) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
FirebaseUser user = firebaseAuth.getCurrentUser();
|
||||
Log.d(TAG, "getCurrentUser");
|
||||
if (user == null) {
|
||||
promiseNoUser(promise, false);
|
||||
} else {
|
||||
promiseWithUser(user, promise);
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------
|
||||
* .currentUser methods
|
||||
* ---------------------- */
|
||||
|
@ -601,16 +619,17 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* signInWithCredential
|
||||
*
|
||||
* @param provider
|
||||
* @param authToken
|
||||
* @param authSecret
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void signInWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
signInWithCredential(appName, provider, authToken, authSecret, promise, false);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void signInAndRetrieveDataWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
signInWithCredential(appName, provider, authToken, authSecret, promise, true);
|
||||
}
|
||||
|
||||
public void signInWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
|
@ -626,7 +645,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
public void onComplete(@NonNull Task<AuthResult> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "signInWithCredential:onComplete:success");
|
||||
if (withData) {
|
||||
promiseWithAuthResult(task.getResult(), promise);
|
||||
} else {
|
||||
promiseWithUser(task.getResult().getUser(), promise);
|
||||
}
|
||||
} else {
|
||||
Exception exception = task.getException();
|
||||
Log.e(TAG, "signInWithCredential:onComplete:failure", exception);
|
||||
|
@ -954,7 +977,7 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
|
||||
/**
|
||||
* link
|
||||
* linkWithCredential
|
||||
*
|
||||
* @param provider
|
||||
* @param authToken
|
||||
|
@ -962,7 +985,16 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void link(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
public void linkWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
link(appName, provider, authToken, authSecret, promise, false);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void linkAndRetrieveDataWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
link(appName, provider, authToken, authSecret, promise, true);
|
||||
}
|
||||
|
||||
private void link(String appName, String provider, String authToken, String authSecret, final Promise promise, final boolean withData) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
|
@ -981,7 +1013,11 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
public void onComplete(@NonNull Task<AuthResult> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "link:onComplete:success");
|
||||
if (withData) {
|
||||
promiseWithAuthResult(task.getResult(), promise);
|
||||
} else {
|
||||
promiseWithUser(task.getResult().getUser(), promise);
|
||||
}
|
||||
} else {
|
||||
Exception exception = task.getException();
|
||||
Log.e(TAG, "link:onComplete:failure", exception);
|
||||
|
@ -995,13 +1031,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* unlink
|
||||
*
|
||||
* @param providerId
|
||||
* @param promise
|
||||
* @url https://firebase.google.com/docs/reference/android/com/google/firebase/auth/FirebaseUser.html#unlink(java.lang.String)
|
||||
*/
|
||||
@ReactMethod
|
||||
public void unlink(final String appName, final String providerId, final Promise promise) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
|
@ -1029,16 +1058,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* reauthenticate
|
||||
*
|
||||
* @param provider
|
||||
* @param authToken
|
||||
* @param authSecret
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void reauthenticate(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
public void reauthenticateWithCredential(String appName, String provider, String authToken, String authSecret, final Promise promise) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
final FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
|
@ -1073,11 +1094,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
|
||||
/**
|
||||
* Returns an instance of AuthCredential for the specified provider
|
||||
*
|
||||
* @param provider
|
||||
* @param authToken
|
||||
* @param authSecret
|
||||
* @return
|
||||
*/
|
||||
private AuthCredential getCredentialForProvider(String provider, String authToken, String authSecret) {
|
||||
switch (provider) {
|
||||
|
@ -1089,6 +1105,8 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
return TwitterAuthProvider.getCredential(authToken, authSecret);
|
||||
case "github.com":
|
||||
return GithubAuthProvider.getCredential(authToken);
|
||||
case "oauth":
|
||||
return OAuthProvider.getCredential(provider, authToken, authSecret);
|
||||
case "phone":
|
||||
// If the phone number is auto-verified quickly, then the verificationId can be null
|
||||
// We cached the credential as part of the verifyPhoneNumber request to be re-used here
|
||||
|
@ -1107,11 +1125,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* getToken
|
||||
*
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void getToken(String appName, Boolean forceRefresh, final Promise promise) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
|
@ -1140,11 +1153,6 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* fetchProvidersForEmail
|
||||
*
|
||||
* @param promise
|
||||
*/
|
||||
@ReactMethod
|
||||
public void fetchProvidersForEmail(String appName, String email, final Promise promise) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
|
@ -1177,6 +1185,44 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
});
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void setLanguageCode(String appName, String code) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
firebaseAuth.setLanguageCode(code);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void useDeviceLanguage(String appName) {
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
firebaseAuth.useAppLanguage();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void verifyPasswordResetCode(String appName, String code, final Promise promise) {
|
||||
Log.d(TAG, "verifyPasswordResetCode");
|
||||
|
||||
FirebaseApp firebaseApp = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(firebaseApp);
|
||||
|
||||
firebaseAuth.verifyPasswordResetCode(code).addOnCompleteListener(new OnCompleteListener<String>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<String> task) {
|
||||
if (task.isSuccessful()) {
|
||||
Log.d(TAG, "verifyPasswordResetCode:onComplete:success");
|
||||
promise.resolve(task.getResult());
|
||||
} else {
|
||||
Exception exception = task.getException();
|
||||
Log.e(TAG, "verifyPasswordResetCode:onComplete:failure", exception);
|
||||
promiseRejectAuthException(promise, exception);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* ------------------
|
||||
* INTERNAL HELPERS
|
||||
* ---------------- */
|
||||
|
@ -1210,6 +1256,97 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* promiseWithAuthResult
|
||||
*
|
||||
* @param authResult
|
||||
* @param promise
|
||||
*/
|
||||
private void promiseWithAuthResult(AuthResult authResult, Promise promise) {
|
||||
if (authResult != null && authResult.getUser() != null) {
|
||||
WritableMap userMap = firebaseUserToMap(authResult.getUser());
|
||||
WritableMap authResultMap = Arguments.createMap();
|
||||
if (authResult.getAdditionalUserInfo() != null) {
|
||||
WritableMap additionalUserInfoMap = Arguments.createMap();
|
||||
additionalUserInfoMap.putBoolean("isNewUser", authResult.getAdditionalUserInfo().isNewUser());
|
||||
if (authResult.getAdditionalUserInfo().getProfile() != null) {
|
||||
WritableMap profileMap = mapToWritableMap(authResult.getAdditionalUserInfo().getProfile());
|
||||
additionalUserInfoMap.putMap("profile", profileMap);
|
||||
}
|
||||
if (authResult.getAdditionalUserInfo().getProviderId() != null) {
|
||||
additionalUserInfoMap.putString("providerId", authResult.getAdditionalUserInfo().getProviderId());
|
||||
}
|
||||
if (authResult.getAdditionalUserInfo().getUsername() != null) {
|
||||
additionalUserInfoMap.putString("username", authResult.getAdditionalUserInfo().getUsername());
|
||||
}
|
||||
authResultMap.putMap("additionalUserInfo", additionalUserInfoMap);
|
||||
}
|
||||
authResultMap.putMap("user", userMap);
|
||||
promise.resolve(authResultMap);
|
||||
} else {
|
||||
promiseNoUser(promise, true);
|
||||
}
|
||||
}
|
||||
|
||||
private WritableMap mapToWritableMap(Map<String, Object> map) {
|
||||
WritableMap writableMap = Arguments.createMap();
|
||||
for (String key : map.keySet()) {
|
||||
Object value = map.get(key);
|
||||
if (value == null) {
|
||||
writableMap.putNull(key);
|
||||
} else if (value instanceof Boolean) {
|
||||
writableMap.putBoolean(key, (Boolean) value);
|
||||
} else if (value instanceof Integer) {
|
||||
writableMap.putDouble(key, ((Integer) value).doubleValue());
|
||||
} else if (value instanceof Long) {
|
||||
writableMap.putDouble(key, ((Long) value).doubleValue());
|
||||
} else if (value instanceof Double) {
|
||||
writableMap.putDouble(key, (Double) value);
|
||||
} else if (value instanceof Float) {
|
||||
writableMap.putDouble(key, ((Float) value).doubleValue());
|
||||
} else if (value instanceof String) {
|
||||
writableMap.putString(key, (String) value);
|
||||
} else if (Map.class.isAssignableFrom(value.getClass())) {
|
||||
writableMap.putMap(key, mapToWritableMap((Map<String, Object>) value));
|
||||
} else if (List.class.isAssignableFrom(value.getClass())) {
|
||||
writableMap.putArray(key, listToWritableArray((List<Object>) value));
|
||||
} else {
|
||||
Log.e(TAG, "mapToWritableMap: Cannot convert object of type " + value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
return writableMap;
|
||||
}
|
||||
|
||||
private WritableArray listToWritableArray(List<Object> list) {
|
||||
WritableArray writableArray = Arguments.createArray();
|
||||
for (Object item : list) {
|
||||
if (item == null) {
|
||||
writableArray.pushNull();
|
||||
} else if (item instanceof Boolean) {
|
||||
writableArray.pushBoolean((Boolean) item);
|
||||
} else if (item instanceof Integer) {
|
||||
writableArray.pushDouble(((Integer) item).doubleValue());
|
||||
} else if (item instanceof Long) {
|
||||
writableArray.pushDouble(((Long) item).doubleValue());
|
||||
} else if (item instanceof Double) {
|
||||
writableArray.pushDouble((Double) item);
|
||||
} else if (item instanceof Float) {
|
||||
writableArray.pushDouble(((Float) item).doubleValue());
|
||||
} else if (item instanceof String) {
|
||||
writableArray.pushString((String) item);
|
||||
} else if (Map.class.isAssignableFrom(item.getClass())) {
|
||||
writableArray.pushMap(mapToWritableMap((Map<String, Object>) item));
|
||||
} else if (List.class.isAssignableFrom(item.getClass())) {
|
||||
writableArray.pushArray(listToWritableArray((List<Object>) item));
|
||||
} else {
|
||||
Log.e(TAG, "listToWritableArray: Cannot convert object of type " + item.getClass());
|
||||
}
|
||||
}
|
||||
return writableArray;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* promiseRejectAuthException
|
||||
*
|
||||
|
@ -1410,6 +1547,14 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
|
||||
userMap.putArray("providerData", convertProviderData(user.getProviderData(), user));
|
||||
|
||||
WritableMap metadataMap = Arguments.createMap();
|
||||
FirebaseUserMetadata metadata = user.getMetadata();
|
||||
if (metadata != null) {
|
||||
metadataMap.putDouble("creationTime", metadata.getCreationTimestamp());
|
||||
metadataMap.putDouble("lastSignInTime", metadata.getLastSignInTimestamp());
|
||||
}
|
||||
userMap.putMap("metadata", metadataMap);
|
||||
|
||||
return userMap;
|
||||
}
|
||||
|
||||
|
@ -1451,4 +1596,29 @@ class RNFirebaseAuth extends ReactContextBaseJavaModule {
|
|||
eventMap.putMap("state", state);
|
||||
Utils.sendEvent(mReactContext, "phone_auth_state_changed", eventMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constants bootstrapped on react native app boot
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public Map<String, Object> getConstants() {
|
||||
Map<String, Object> constants = new HashMap<>();
|
||||
|
||||
List<FirebaseApp> firebaseAppList = FirebaseApp.getApps(getReactApplicationContext());
|
||||
final Map<String, Object> appLanguage = new HashMap<>();
|
||||
|
||||
for (FirebaseApp app : firebaseAppList) {
|
||||
String appName = app.getName();
|
||||
|
||||
FirebaseApp instance = FirebaseApp.getInstance(appName);
|
||||
FirebaseAuth firebaseAuth = FirebaseAuth.getInstance(instance);
|
||||
|
||||
appLanguage.put(appName, firebaseAuth.getLanguageCode());
|
||||
}
|
||||
|
||||
constants.put("APP_LANGUAGE", appLanguage);
|
||||
return constants;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import com.facebook.react.bridge.WritableMap;
|
|||
import com.google.firebase.firestore.DocumentChange;
|
||||
import com.google.firebase.firestore.DocumentReference;
|
||||
import com.google.firebase.firestore.DocumentSnapshot;
|
||||
import com.google.firebase.firestore.FieldPath;
|
||||
import com.google.firebase.firestore.FieldValue;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.GeoPoint;
|
||||
|
@ -214,7 +215,6 @@ public class FirestoreSerialize {
|
|||
typeMap.putString("type", "date");
|
||||
typeMap.putDouble("value", ((Date) value).getTime());
|
||||
} else {
|
||||
// TODO: Changed to log an error rather than crash - is this correct?
|
||||
Log.e(TAG, "buildTypeMap: Cannot convert object of type " + value.getClass());
|
||||
typeMap.putString("type", "null");
|
||||
typeMap.putNull("value");
|
||||
|
@ -269,6 +269,8 @@ public class FirestoreSerialize {
|
|||
} else if ("date".equals(type)) {
|
||||
Double time = typeMap.getDouble("value");
|
||||
return new Date(time.longValue());
|
||||
} else if ("documentid".equals(type)) {
|
||||
return FieldPath.documentId();
|
||||
} else if ("fieldvalue".equals(type)) {
|
||||
String value = typeMap.getString("value");
|
||||
if ("delete".equals(value)) {
|
||||
|
|
|
@ -14,6 +14,7 @@ import com.google.android.gms.tasks.OnCompleteListener;
|
|||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.firebase.firestore.DocumentListenOptions;
|
||||
import com.google.firebase.firestore.EventListener;
|
||||
import com.google.firebase.firestore.FieldPath;
|
||||
import com.google.firebase.firestore.FirebaseFirestore;
|
||||
import com.google.firebase.firestore.FirebaseFirestoreException;
|
||||
import com.google.firebase.firestore.ListenerRegistration;
|
||||
|
@ -21,6 +22,7 @@ import com.google.firebase.firestore.Query;
|
|||
import com.google.firebase.firestore.QueryListenOptions;
|
||||
import com.google.firebase.firestore.QuerySnapshot;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -128,11 +130,39 @@ public class RNFirebaseFirestoreCollectionReference {
|
|||
private Query applyFilters(FirebaseFirestore firestore, Query query) {
|
||||
for (int i = 0; i < filters.size(); i++) {
|
||||
ReadableMap filter = filters.getMap(i);
|
||||
String fieldPath = filter.getString("fieldPath");
|
||||
ReadableMap fieldPathMap = filter.getMap("fieldPath");
|
||||
String fieldPathType = fieldPathMap.getString("type");
|
||||
|
||||
String operator = filter.getString("operator");
|
||||
ReadableMap jsValue = filter.getMap("value");
|
||||
Object value = FirestoreSerialize.parseTypeMap(firestore, jsValue);
|
||||
|
||||
if (fieldPathType.equals("string")) {
|
||||
String fieldPath = fieldPathMap.getString("string");
|
||||
switch (operator) {
|
||||
case "EQUAL":
|
||||
query = query.whereEqualTo(fieldPath, value);
|
||||
break;
|
||||
case "GREATER_THAN":
|
||||
query = query.whereGreaterThan(fieldPath, value);
|
||||
break;
|
||||
case "GREATER_THAN_OR_EQUAL":
|
||||
query = query.whereGreaterThanOrEqualTo(fieldPath, value);
|
||||
break;
|
||||
case "LESS_THAN":
|
||||
query = query.whereLessThan(fieldPath, value);
|
||||
break;
|
||||
case "LESS_THAN_OR_EQUAL":
|
||||
query = query.whereLessThanOrEqualTo(fieldPath, value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ReadableArray fieldPathElements = fieldPathMap.getArray("elements");
|
||||
String[] fieldPathArray = new String[fieldPathElements.size()];
|
||||
for (int j=0; j<fieldPathElements.size(); j++) {
|
||||
fieldPathArray[j] = fieldPathElements.getString(j);
|
||||
}
|
||||
FieldPath fieldPath = FieldPath.of(fieldPathArray);
|
||||
switch (operator) {
|
||||
case "EQUAL":
|
||||
query = query.whereEqualTo(fieldPath, value);
|
||||
|
@ -151,6 +181,7 @@ public class RNFirebaseFirestoreCollectionReference {
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
||||
|
@ -159,9 +190,17 @@ public class RNFirebaseFirestoreCollectionReference {
|
|||
for (Object o : ordersList) {
|
||||
Map<String, Object> order = (Map) o;
|
||||
String direction = (String) order.get("direction");
|
||||
String fieldPath = (String) order.get("fieldPath");
|
||||
Map<String, Object> fieldPathMap = (Map) order.get("fieldPath");
|
||||
String fieldPathType = (String)fieldPathMap.get("type");
|
||||
|
||||
if (fieldPathType.equals("string")) {
|
||||
String fieldPath = (String)fieldPathMap.get("string");
|
||||
query = query.orderBy(fieldPath, Query.Direction.valueOf(direction));
|
||||
} else {
|
||||
List<String> fieldPathElements = (List)fieldPathMap.get("elements");
|
||||
FieldPath fieldPath = FieldPath.of(fieldPathElements.toArray(new String[fieldPathElements.size()]));
|
||||
query = query.orderBy(fieldPath, Query.Direction.valueOf(direction));
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
|
|
@ -453,31 +453,15 @@
|
|||
ENABLE_BITCODE = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"${BUILT_PRODUCTS_DIR}",
|
||||
"${SRCROOT}/../../../ios/Pods/Crashlytics/iOS",
|
||||
"${SRCROOT}/../../../ios/Pods/Fabric/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseAnalytics/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseAuth/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseCore/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseCrash/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseDatabase/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseDynamicLinks/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseFirestore/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseInstanceID/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseMessaging/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebasePerformance/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseRemoteConfig/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseStorage/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/Google-Mobile-Ads-SDK/Frameworks/frameworks",
|
||||
"${BUILT_PRODUCTS_DIR}/**",
|
||||
"${SRCROOT}/../../../ios/Pods/**",
|
||||
"${SRCROOT}/../../../ios/Firebase/**",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../../react-native/React/**",
|
||||
"${SRCROOT}/../../../ios/Firebase/**",
|
||||
"${SRCROOT}/../../../ios/Pods/Headers/Public/Crashlytics",
|
||||
"${SRCROOT}/../../../ios/Pods/Headers/Public/Fabric",
|
||||
"${SRCROOT}/../../../ios/Pods/Firebase/**",
|
||||
"${SRCROOT}/../../../ios/Pods/Headers/Public/**",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
|
@ -498,31 +482,15 @@
|
|||
ENABLE_BITCODE = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"${BUILT_PRODUCTS_DIR}",
|
||||
"${SRCROOT}/../../../ios/Pods/Crashlytics/iOS",
|
||||
"${SRCROOT}/../../../ios/Pods/Fabric/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseAnalytics/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseAuth/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseCore/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseCrash/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseDatabase/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseDynamicLinks/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseFirestore/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseInstanceID/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseMessaging/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebasePerformance/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseRemoteConfig/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/FirebaseStorage/Frameworks",
|
||||
"${SRCROOT}/../../../ios/Pods/Google-Mobile-Ads-SDK/Frameworks/frameworks",
|
||||
"${BUILT_PRODUCTS_DIR}/**",
|
||||
"${SRCROOT}/../../../ios/Pods/**",
|
||||
"${SRCROOT}/../../../ios/Firebase/**",
|
||||
);
|
||||
HEADER_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"$(SRCROOT)/../../react-native/React/**",
|
||||
"${SRCROOT}/../../../ios/Firebase/**",
|
||||
"${SRCROOT}/../../../ios/Pods/Headers/Public/Crashlytics",
|
||||
"${SRCROOT}/../../../ios/Pods/Headers/Public/Fabric",
|
||||
"${SRCROOT}/../../../ios/Pods/Firebase/**",
|
||||
"${SRCROOT}/../../../ios/Pods/Headers/Public/**",
|
||||
);
|
||||
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
static NSString *const AUTH_CHANGED_EVENT = @"auth_state_changed";
|
||||
static NSString *const AUTH_STATE_CHANGED_EVENT = @"auth_state_changed";
|
||||
static NSString *const AUTH_ID_TOKEN_CHANGED_EVENT = @"auth_id_token_changed";
|
||||
static NSString *const PHONE_AUTH_STATE_CHANGED_EVENT = @"phone_auth_state_changed";
|
||||
|
||||
|
|
|
@ -29,9 +29,9 @@ RCT_EXPORT_METHOD(addAuthStateListener:
|
|||
if (![_authStateHandlers valueForKey:firApp.name]) {
|
||||
FIRAuthStateDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth, FIRUser *_Nullable user) {
|
||||
if (user != nil) {
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_STATE_CHANGED_EVENT body:@{@"user": [self firebaseUserToDict:user]}];
|
||||
} else {
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_CHANGED_EVENT body:@{@"authenticated": @(false)}];
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_STATE_CHANGED_EVENT body:@{}];
|
||||
}
|
||||
}];
|
||||
|
||||
|
@ -64,9 +64,9 @@ RCT_EXPORT_METHOD(addIdTokenListener:
|
|||
if (![_idTokenHandlers valueForKey:firApp.name]) {
|
||||
FIRIDTokenDidChangeListenerHandle newListenerHandle = [[FIRAuth authWithApp:firApp] addIDTokenDidChangeListener:^(FIRAuth * _Nonnull auth, FIRUser * _Nullable user) {
|
||||
if (user != nil) {
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(true), @"user": [self firebaseUserToDict:user]}];
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"user": [self firebaseUserToDict:user]}];
|
||||
} else {
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{@"authenticated": @(false)}];
|
||||
[RNFirebaseUtil sendJSEventWithAppName:self app:firApp name:AUTH_ID_TOKEN_CHANGED_EVENT body:@{}];
|
||||
}
|
||||
}];
|
||||
|
||||
|
@ -125,12 +125,9 @@ RCT_EXPORT_METHOD(signOut:
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInAnonymously:
|
||||
(NSString *) appDisplayName
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInAnonymously:(NSString *) appDisplayName
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] signInAnonymouslyWithCompletion:^(FIRUser *user, NSError *error) {
|
||||
|
@ -140,7 +137,27 @@ RCT_EXPORT_METHOD(signInAnonymously:
|
|||
[self promiseWithUser:resolve rejecter:reject user:user];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
signInAnonymouslyAndRetrieveData
|
||||
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInAnonymouslyAndRetrieveData:(NSString *) appDisplayName
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] signInAnonymouslyAndRetrieveDataWithCompletion:^(FIRAuthDataResult *authResult, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,16 +169,11 @@ RCT_EXPORT_METHOD(signInAnonymously:
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInWithEmailAndPassword:
|
||||
(NSString *) appDisplayName
|
||||
email:
|
||||
(NSString *) email
|
||||
pass:
|
||||
(NSString *) password
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInWithEmailAndPassword:(NSString *) appDisplayName
|
||||
email:(NSString *) email
|
||||
pass:(NSString *) password
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] signInWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
|
||||
|
@ -173,6 +185,31 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:
|
|||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
signInAndRetrieveDataWithEmailAndPassword
|
||||
|
||||
@param NSString NSString email
|
||||
@param NSString NSString password
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInAndRetrieveDataWithEmailAndPassword:(NSString *) appDisplayName
|
||||
email:(NSString *) email
|
||||
pass:(NSString *) password
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithEmail:email password:password completion:^(FIRAuthDataResult *authResult, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
createUserWithEmailAndPassword
|
||||
|
||||
|
@ -182,16 +219,11 @@ RCT_EXPORT_METHOD(signInWithEmailAndPassword:
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(createUserWithEmailAndPassword:
|
||||
(NSString *) appDisplayName
|
||||
email:
|
||||
(NSString *) email
|
||||
pass:
|
||||
(NSString *) password
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(createUserWithEmailAndPassword:(NSString *) appDisplayName
|
||||
email:(NSString *) email
|
||||
pass:(NSString *) password
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] createUserWithEmail:email password:password completion:^(FIRUser *user, NSError *error) {
|
||||
|
@ -203,6 +235,32 @@ RCT_EXPORT_METHOD(createUserWithEmailAndPassword:
|
|||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
createUserAndRetrieveDataWithEmailAndPassword
|
||||
|
||||
@param NSString NSString email
|
||||
@param NSString NSString password
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(createUserAndRetrieveDataWithEmailAndPassword:(NSString *) appDisplayName
|
||||
email:(NSString *) email
|
||||
pass:(NSString *) password
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] createUserAndRetrieveDataWithEmail:email password:password
|
||||
completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
deleteUser
|
||||
|
||||
|
@ -447,18 +505,12 @@ RCT_EXPORT_METHOD(getToken:
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInWithCredential:
|
||||
(NSString *) appDisplayName
|
||||
provider:
|
||||
(NSString *) provider
|
||||
token:
|
||||
(NSString *) authToken
|
||||
secret:
|
||||
(NSString *) authSecret
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInWithCredential:(NSString *) appDisplayName
|
||||
provider:(NSString *) provider
|
||||
token:(NSString *) authToken
|
||||
secret:(NSString *) authSecret
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
@ -476,6 +528,39 @@ RCT_EXPORT_METHOD(signInWithCredential:
|
|||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
signInAndRetrieveDataWithCredential
|
||||
|
||||
@param NSString provider
|
||||
@param NSString authToken
|
||||
@param NSString authSecret
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInAndRetrieveDataWithCredential:(NSString *) appDisplayName
|
||||
provider:(NSString *) provider
|
||||
token:(NSString *) authToken
|
||||
secret:(NSString *) authSecret
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
||||
if (credential == nil) {
|
||||
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
|
||||
}
|
||||
|
||||
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithCredential:credential completion:^(FIRAuthDataResult *authResult, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
/**
|
||||
confirmPasswordReset
|
||||
|
||||
|
@ -610,26 +695,29 @@ RCT_EXPORT_METHOD(sendPasswordResetEmail:(NSString *) appDisplayName
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
getCurrentUser
|
||||
signInAndRetrieveDataWithCustomToken
|
||||
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(getCurrentUser:
|
||||
(NSString *) appDisplayName
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInAndRetrieveDataWithCustomToken:(NSString *) appDisplayName
|
||||
customToken:(NSString *) customToken
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
|
||||
[self promiseWithUser:resolve rejecter:reject user:user];
|
||||
[[FIRAuth authWithApp:firApp] signInAndRetrieveDataWithCustomToken:customToken completion:^(FIRAuthDataResult *authResult, NSError *error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
signInWithCustomToken
|
||||
|
||||
|
@ -637,14 +725,10 @@ RCT_EXPORT_METHOD(getCurrentUser:
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(signInWithCustomToken:
|
||||
(NSString *) appDisplayName
|
||||
customToken:
|
||||
(NSString *) customToken
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(signInWithCustomToken:(NSString *) appDisplayName
|
||||
customToken:(NSString *) customToken
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] signInWithCustomToken:customToken completion:^(FIRUser *user, NSError *error) {
|
||||
|
@ -737,7 +821,7 @@ RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appDisplayName
|
|||
}
|
||||
|
||||
/**
|
||||
link - *insert zelda joke here*
|
||||
linkWithCredential
|
||||
|
||||
@param NSString provider
|
||||
@param NSString authToken
|
||||
|
@ -746,20 +830,13 @@ RCT_EXPORT_METHOD(_confirmVerificationCode:(NSString *) appDisplayName
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(link:
|
||||
(NSString *) appDisplayName
|
||||
provider:
|
||||
(NSString *) provider
|
||||
authToken:
|
||||
(NSString *) authToken
|
||||
authSecret:
|
||||
(NSString *) authSecret
|
||||
resolver:
|
||||
(RCTPromiseResolveBlock) resolve
|
||||
rejecter:
|
||||
(RCTPromiseRejectBlock) reject) {
|
||||
RCT_EXPORT_METHOD(linkWithCredential:(NSString *) appDisplayName
|
||||
provider:(NSString *) provider
|
||||
authToken:(NSString *) authToken
|
||||
authSecret:(NSString *) authSecret
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
||||
if (credential == nil) {
|
||||
|
@ -781,6 +858,44 @@ RCT_EXPORT_METHOD(link:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
linkAndRetrieveDataWithCredential
|
||||
|
||||
@param NSString provider
|
||||
@param NSString authToken
|
||||
@param NSString authSecret
|
||||
@param RCTPromiseResolveBlock resolve
|
||||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(linkAndRetrieveDataWithCredential:(NSString *) appDisplayName
|
||||
provider:(NSString *) provider
|
||||
authToken:(NSString *) authToken
|
||||
authSecret:(NSString *) authSecret
|
||||
resolver:(RCTPromiseResolveBlock) resolve
|
||||
rejecter:(RCTPromiseRejectBlock) reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
FIRAuthCredential *credential = [self getCredentialForProvider:provider token:authToken secret:authSecret];
|
||||
|
||||
if (credential == nil) {
|
||||
return reject(@"auth/invalid-credential", @"The supplied auth credential is malformed, has expired or is not currently supported.", nil);
|
||||
}
|
||||
|
||||
FIRUser *user = [FIRAuth authWithApp:firApp].currentUser;
|
||||
if (user) {
|
||||
[user linkAndRetrieveDataWithCredential:credential
|
||||
completion:^(FIRAuthDataResult * _Nullable authResult, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
[self promiseWithAuthResult:resolve rejecter:reject authResult:authResult];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[self promiseNoUser:resolve rejecter:reject isError:YES];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
unlink
|
||||
|
||||
|
@ -816,7 +931,7 @@ RCT_EXPORT_METHOD(unlink:
|
|||
}
|
||||
|
||||
/**
|
||||
reauthenticate
|
||||
reauthenticateWithCredential
|
||||
|
||||
@param NSString provider
|
||||
@param NSString authToken
|
||||
|
@ -825,7 +940,7 @@ RCT_EXPORT_METHOD(unlink:
|
|||
@param RCTPromiseRejectBlock reject
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(reauthenticate:
|
||||
RCT_EXPORT_METHOD(reauthenticateWithCredential:
|
||||
(NSString *) appDisplayName
|
||||
provider:
|
||||
(NSString *) provider
|
||||
|
@ -914,6 +1029,8 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
|||
credential = [FIRGitHubAuthProvider credentialWithToken:authToken];
|
||||
} else if ([provider compare:@"phone" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
credential = [[FIRPhoneAuthProvider provider] credentialWithVerificationID:authToken verificationCode:authTokenSecret];
|
||||
} else if ([provider compare:@"oauth" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
|
||||
credential = [FIROAuthProvider credentialWithProviderID:@"oauth" IDToken:authToken accessToken:authTokenSecret];
|
||||
} else {
|
||||
NSLog(@"Provider not yet handled: %@", provider);
|
||||
}
|
||||
|
@ -921,6 +1038,47 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
|||
return credential;
|
||||
}
|
||||
|
||||
/**
|
||||
setLanguageCode
|
||||
|
||||
@param NSString code
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setLanguageCode:
|
||||
(NSString *) appDisplayName
|
||||
code:
|
||||
(NSString *) code) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[FIRAuth authWithApp:firApp].languageCode = code;
|
||||
}
|
||||
|
||||
/**
|
||||
useDeviceLanguage
|
||||
|
||||
@param NSString code
|
||||
@return
|
||||
*/
|
||||
RCT_EXPORT_METHOD(useDeviceLanguage:(NSString *) appDisplayName) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
|
||||
[[FIRAuth authWithApp:firApp] useAppLanguage];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(verifyPasswordResetCode:(NSString *) appDisplayName
|
||||
code:(NSString *)code
|
||||
resolver:(RCTPromiseResolveBlock)resolve
|
||||
rejecter:(RCTPromiseRejectBlock)reject) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
[[FIRAuth authWithApp:firApp] verifyPasswordResetCode:code completion:^(NSString * _Nullable email, NSError * _Nullable error) {
|
||||
if (error) {
|
||||
[self promiseRejectAuthException:reject error:error];
|
||||
} else {
|
||||
resolve(email);
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
// This is here to protect against bugs in the iOS SDK which don't
|
||||
// correctly refresh the user object when performing certain operations
|
||||
- (void)reloadAndReturnUser:(FIRUser *)user
|
||||
|
@ -1105,6 +1263,32 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
Resolve or reject a promise based on FIRAuthResult value existance
|
||||
|
||||
@param resolve RCTPromiseResolveBlock
|
||||
@param reject RCTPromiseRejectBlock
|
||||
@param authResult FIRAuthDataResult
|
||||
*/
|
||||
- (void)promiseWithAuthResult:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject authResult:(FIRAuthDataResult *)authResult {
|
||||
if (authResult && authResult.user) {
|
||||
NSDictionary *userDict = [self firebaseUserToDict:authResult.user];
|
||||
NSDictionary *authResultDict = @{
|
||||
@"additionalUserInfo": authResult.additionalUserInfo ? @{
|
||||
@"isNewUser": @(authResult.additionalUserInfo.isNewUser),
|
||||
@"profile": authResult.additionalUserInfo.profile ? authResult.additionalUserInfo.profile : [NSNull null],
|
||||
@"providerId": authResult.additionalUserInfo.providerID ? authResult.additionalUserInfo.providerID : [NSNull null],
|
||||
@"username": authResult.additionalUserInfo.username ? authResult.additionalUserInfo.username : [NSNull null]
|
||||
} : [NSNull null],
|
||||
@"user": userDict
|
||||
};
|
||||
resolve(authResultDict);
|
||||
} else {
|
||||
[self promiseNoUser:resolve rejecter:reject isError:YES];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
Converts an array of FIRUserInfo instances into the correct format to match the web sdk
|
||||
|
||||
|
@ -1147,20 +1331,48 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
|||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* React native constant exports - exports native firebase apps mainly
|
||||
* @return NSDictionary
|
||||
*/
|
||||
- (NSDictionary *)constantsToExport {
|
||||
NSMutableDictionary *constants = [NSMutableDictionary new];
|
||||
NSDictionary *firApps = [FIRApp allApps];
|
||||
NSMutableDictionary *appLanguage = [NSMutableDictionary new];
|
||||
|
||||
for (id key in firApps) {
|
||||
FIRApp *firApp = firApps[key];
|
||||
|
||||
appLanguage[firApp.name] = [FIRAuth authWithApp:firApp].languageCode;
|
||||
}
|
||||
|
||||
constants[@"APP_LANGUAGE"] = appLanguage;
|
||||
return constants;
|
||||
}
|
||||
|
||||
/**
|
||||
Converts a FIRUser instance into a dictionary to send via RNBridge
|
||||
|
||||
@param user FIRUser
|
||||
@return NSDictionary
|
||||
*/
|
||||
- (NSMutableDictionary *)firebaseUserToDict:(FIRUser *)user {
|
||||
NSMutableDictionary *userDict = [@{@"uid": user.uid, @"email": user.email ? user.email : [NSNull null], @"emailVerified": @(user.emailVerified), @"isAnonymous": @(user.anonymous), @"displayName": user.displayName ? user.displayName : [NSNull null], @"refreshToken": user.refreshToken, @"providerId": [user.providerID lowercaseString], @"phoneNumber": user.phoneNumber ? user.phoneNumber : [NSNull null], @"providerData": [self convertProviderData:user.providerData]} mutableCopy];
|
||||
|
||||
if ([user valueForKey:@"photoURL"] != nil) {
|
||||
[userDict setValue:[user.photoURL absoluteString] forKey:@"photoURL"];
|
||||
}
|
||||
|
||||
return userDict;
|
||||
- (NSDictionary *)firebaseUserToDict:(FIRUser *)user {
|
||||
return @{
|
||||
@"displayName": user.displayName ? user.displayName : [NSNull null],
|
||||
@"email": user.email ? user.email : [NSNull null],
|
||||
@"emailVerified": @(user.emailVerified),
|
||||
@"isAnonymous": @(user.anonymous),
|
||||
@"metadata": @{
|
||||
@"creationTime": user.metadata.creationDate ? @(round([user.metadata.creationDate timeIntervalSince1970] * 1000.0)): [NSNull null],
|
||||
@"lastSignInTime": user.metadata.lastSignInDate ? @(round([user.metadata.lastSignInDate timeIntervalSince1970] * 1000.0)) : [NSNull null],
|
||||
},
|
||||
@"phoneNumber": user.phoneNumber ? user.phoneNumber : [NSNull null],
|
||||
@"photoURL": user.photoURL ? [user.photoURL absoluteString] : [NSNull null],
|
||||
@"providerData": [self convertProviderData:user.providerData],
|
||||
@"providerId": [user.providerID lowercaseString],
|
||||
@"refreshToken": user.refreshToken,
|
||||
@"uid": user.uid
|
||||
};
|
||||
}
|
||||
|
||||
- (FIRActionCodeSettings *)buildActionCodeSettings:(NSDictionary *)actionCodeSettings {
|
||||
|
@ -1188,7 +1400,7 @@ RCT_EXPORT_METHOD(fetchProvidersForEmail:
|
|||
}
|
||||
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[AUTH_CHANGED_EVENT, AUTH_ID_TOKEN_CHANGED_EVENT, PHONE_AUTH_STATE_CHANGED_EVENT];
|
||||
return @[AUTH_STATE_CHANGED_EVENT, AUTH_ID_TOKEN_CHANGED_EVENT, PHONE_AUTH_STATE_CHANGED_EVENT];
|
||||
}
|
||||
|
||||
+ (BOOL)requiresMainQueueSetup
|
||||
|
|
|
@ -93,11 +93,14 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
|||
- (FIRQuery *)applyFilters:(FIRFirestore *) firestore
|
||||
query:(FIRQuery *) query {
|
||||
for (NSDictionary *filter in _filters) {
|
||||
NSString *fieldPath = filter[@"fieldPath"];
|
||||
NSDictionary *fieldPathDictionary = filter[@"fieldPath"];
|
||||
NSString *fieldPathType = fieldPathDictionary[@"type"];
|
||||
NSString *operator = filter[@"operator"];
|
||||
NSDictionary *jsValue = filter[@"value"];
|
||||
id value = [RNFirebaseFirestoreDocumentReference parseJSTypeMap:firestore jsTypeMap:jsValue];
|
||||
|
||||
if ([fieldPathType isEqualToString:@"string"]) {
|
||||
NSString *fieldPath = fieldPathDictionary[@"string"];
|
||||
if ([operator isEqualToString:@"EQUAL"]) {
|
||||
query = [query queryWhereField:fieldPath isEqualTo:value];
|
||||
} else if ([operator isEqualToString:@"GREATER_THAN"]) {
|
||||
|
@ -109,6 +112,21 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
|||
} else if ([operator isEqualToString:@"LESS_THAN_OR_EQUAL"]) {
|
||||
query = [query queryWhereField:fieldPath isLessThanOrEqualTo:value];
|
||||
}
|
||||
} else {
|
||||
NSArray *fieldPathElements = fieldPathDictionary[@"elements"];
|
||||
FIRFieldPath *fieldPath = [[FIRFieldPath alloc] initWithFields:fieldPathElements];
|
||||
if ([operator isEqualToString:@"EQUAL"]) {
|
||||
query = [query queryWhereFieldPath:fieldPath isEqualTo:value];
|
||||
} else if ([operator isEqualToString:@"GREATER_THAN"]) {
|
||||
query = [query queryWhereFieldPath:fieldPath isGreaterThan:value];
|
||||
} else if ([operator isEqualToString:@"GREATER_THAN_OR_EQUAL"]) {
|
||||
query = [query queryWhereFieldPath:fieldPath isGreaterThanOrEqualTo:value];
|
||||
} else if ([operator isEqualToString:@"LESS_THAN"]) {
|
||||
query = [query queryWhereFieldPath:fieldPath isLessThan:value];
|
||||
} else if ([operator isEqualToString:@"LESS_THAN_OR_EQUAL"]) {
|
||||
query = [query queryWhereFieldPath:fieldPath isLessThanOrEqualTo:value];
|
||||
}
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
@ -116,9 +134,17 @@ queryListenOptions:(NSDictionary *) queryListenOptions {
|
|||
- (FIRQuery *)applyOrders:(FIRQuery *) query {
|
||||
for (NSDictionary *order in _orders) {
|
||||
NSString *direction = order[@"direction"];
|
||||
NSString *fieldPath = order[@"fieldPath"];
|
||||
NSDictionary *fieldPathDictionary = order[@"fieldPath"];
|
||||
NSString *fieldPathType = fieldPathDictionary[@"type"];
|
||||
|
||||
if ([fieldPathType isEqualToString:@"string"]) {
|
||||
NSString *fieldPath = fieldPathDictionary[@"string"];
|
||||
query = [query queryOrderedByField:fieldPath descending:([direction isEqualToString:@"DESCENDING"])];
|
||||
} else {
|
||||
NSArray *fieldPathElements = fieldPathDictionary[@"elements"];
|
||||
FIRFieldPath *fieldPath = [[FIRFieldPath alloc] initWithFields:fieldPathElements];
|
||||
query = [query queryOrderedByFieldPath:fieldPath descending:([direction isEqualToString:@"DESCENDING"])];
|
||||
}
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
|
|
@ -255,6 +255,8 @@ static NSMutableDictionary *_listeners;
|
|||
return [[FIRGeoPoint alloc] initWithLatitude:[latitude doubleValue] longitude:[longitude doubleValue]];
|
||||
} else if ([type isEqualToString:@"date"]) {
|
||||
return [NSDate dateWithTimeIntervalSince1970:([(NSNumber *)value doubleValue] / 1000.0)];
|
||||
} else if ([type isEqualToString:@"documentid"]) {
|
||||
return [FIRFieldPath documentID];
|
||||
} else if ([type isEqualToString:@"fieldvalue"]) {
|
||||
NSString *string = (NSString*)value;
|
||||
if ([string isEqualToString:@"delete"]) {
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
|
||||
|
||||
static void sendDynamicLink(NSURL *url, id sender) {
|
||||
if (url) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:LINKS_DYNAMIC_LINK_RECEIVED
|
||||
object:sender
|
||||
userInfo:@{@"url": url.absoluteString}];
|
||||
NSLog(@"sendDynamicLink Success: %@", url.absoluteString);
|
||||
}
|
||||
}
|
||||
|
||||
@implementation RNFirebaseLinks
|
||||
|
@ -161,9 +163,11 @@ RCT_EXPORT_METHOD(createShortDynamicLink: (NSDictionary *) metadata resolver:(RC
|
|||
NSLog(@"create short dynamic link failure %@", [error localizedDescription]);
|
||||
reject(@"links/failure", @"Failed to create Short Dynamic Link", error);
|
||||
}
|
||||
else {
|
||||
NSURL *shortLink = shortURL;
|
||||
NSLog(@"created short dynamic link: %@", shortLink.absoluteString);
|
||||
resolve(shortLink.absoluteString);
|
||||
}
|
||||
}];
|
||||
}
|
||||
@catch(NSException * e) {
|
||||
|
|
|
@ -45,6 +45,12 @@ RCT_ENUM_CONVERTER(NSCalendarUnit,
|
|||
content.userInfo = details;
|
||||
content.badge = [RCTConvert NSNumber:details[@"badge"]];
|
||||
|
||||
if([details objectForKey:@"show_in_foreground"] != nil) {
|
||||
if([(NSNumber *)details[@"show_in_foreground"] boolValue] == YES) {
|
||||
[content setValue:@YES forKeyPath:@"shouldAlwaysAlertWhileAppIsForeground"];
|
||||
}
|
||||
}
|
||||
|
||||
NSDate *fireDate = [RCTConvert NSDate:details[@"fire_date"]];
|
||||
|
||||
if(fireDate == nil){
|
||||
|
|
|
@ -162,7 +162,7 @@ RCT_EXPORT_METHOD(downloadFile:(NSString *) appDisplayName
|
|||
@param NSNumber milliseconds
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSString *) appDisplayName
|
||||
milliseconds:(NSNumber *) milliseconds) {
|
||||
milliseconds:(nonnull NSNumber *) milliseconds) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
[[FIRStorage storageForApp:firApp] setMaxDownloadRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
@ -174,7 +174,7 @@ RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSString *) appDisplayName
|
|||
@param NSNumber milliseconds
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSString *) appDisplayName
|
||||
milliseconds:(NSNumber *) milliseconds) {
|
||||
milliseconds:(nonnull NSNumber *) milliseconds) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
[[FIRStorage storageForApp:firApp] setMaxOperationRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
@ -185,7 +185,7 @@ RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSString *) appDisplayName
|
|||
@url https://firebase.google.com/docs/reference/js/firebase.storage.Storage#setMaxUploadRetryTime
|
||||
*/
|
||||
RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSString *) appDisplayName
|
||||
milliseconds:(NSNumber *) milliseconds) {
|
||||
milliseconds:(nonnull NSNumber *) milliseconds) {
|
||||
FIRApp *firApp = [RNFirebaseUtil getApp:appDisplayName];
|
||||
[[FIRStorage storageForApp:firApp] setMaxUploadRetryTime:[milliseconds doubleValue]];
|
||||
}
|
||||
|
|
|
@ -3,7 +3,5 @@
|
|||
"allowJs": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
"exclude": ["node_modules"]
|
||||
}
|
|
@ -5,80 +5,77 @@
|
|||
|
||||
declare module "react-native-firebase" {
|
||||
|
||||
type AuthProvider = {
|
||||
PROVIDER_ID: string,
|
||||
credential: (token: string, secret?: string) => object,
|
||||
/** 3rd party provider Credentials */
|
||||
type AuthCredential = {
|
||||
providerId: string,
|
||||
token: string,
|
||||
secret: string
|
||||
}
|
||||
|
||||
type FirebaseModuleAndStatics<M, S = {}> = {
|
||||
(): M;
|
||||
nativeModuleExists: boolean;
|
||||
} & S
|
||||
|
||||
// Modules commented-out do not currently have type definitions
|
||||
export class Firebase {
|
||||
private constructor();
|
||||
// admob: FirebaseModuleAndStatics<RNFirebase.admob.AdMob>;
|
||||
analytics: FirebaseModuleAndStatics<RNFirebase.Analytics>;
|
||||
auth: FirebaseModuleAndStatics<RNFirebase.auth.Auth, RNFirebase.auth.AuthStatics>;
|
||||
// config: FirebaseModule<RNFirebase.config.Config>;
|
||||
crash: FirebaseModuleAndStatics<RNFirebase.crash.Crash>;
|
||||
database: FirebaseModuleAndStatics<RNFirebase.database.Database, RNFirebase.database.DatabaseStatics>;
|
||||
fabric: {
|
||||
crashlytics: FirebaseModuleAndStatics<RNFirebase.crashlytics.Crashlytics>;
|
||||
};
|
||||
firestore: FirebaseModuleAndStatics<RNFirebase.firestore.Firestore, RNFirebase.firestore.FirestoreStatics>;
|
||||
links: FirebaseModuleAndStatics<RNFirebase.links.Links>;
|
||||
messaging: FirebaseModuleAndStatics<RNFirebase.messaging.Messaging>;
|
||||
// perf: FirebaseModuleAndStatics<RNFirebase.perf.Perf>;
|
||||
storage: FirebaseModuleAndStatics<RNFirebase.storage.Storage>;
|
||||
// utils: FirebaseModuleAndStatics<RNFirebase.utils.Utils>;
|
||||
initializeApp(options: Firebase.Options, name: string): App;
|
||||
app(name?: string): App;
|
||||
readonly apps: App[];
|
||||
readonly SDK_VERSION: string;
|
||||
}
|
||||
namespace Firebase {
|
||||
interface Options {
|
||||
apiKey: string;
|
||||
appId: string;
|
||||
databaseURL: string;
|
||||
messagingSenderId: string;
|
||||
projectId: string;
|
||||
storageBucket: string;
|
||||
}
|
||||
}
|
||||
const firebase: Firebase;
|
||||
export default firebase;
|
||||
|
||||
export default class FireBase {
|
||||
constructor(config?: RNFirebase.configurationOptions)
|
||||
|
||||
log: any;
|
||||
|
||||
// Modules commented-out do not currently have type definitions
|
||||
export class App {
|
||||
private constructor();
|
||||
// admob(): RNFirebase.admob.AdMob;
|
||||
analytics(): RNFirebase.Analytics;
|
||||
|
||||
on(type: string, handler: (msg: any) => void): any;
|
||||
|
||||
database: {
|
||||
(): RNFirebase.database.Database
|
||||
ServerValue: {
|
||||
TIMESTAMP: number
|
||||
}
|
||||
};
|
||||
|
||||
auth: {
|
||||
(): RNFirebase.auth.Auth
|
||||
EmailAuthProvider: AuthProvider,
|
||||
PhoneAuthProvider: AuthProvider,
|
||||
GoogleAuthProvider: AuthProvider,
|
||||
GithubAuthProvider: AuthProvider,
|
||||
TwitterAuthProvider: AuthProvider,
|
||||
FacebookAuthProvider: AuthProvider,
|
||||
PhoneAuthState: {
|
||||
CODE_SENT: string,
|
||||
AUTO_VERIFY_TIMEOUT: string,
|
||||
AUTO_VERIFIED: string,
|
||||
ERROR: string,
|
||||
},
|
||||
};
|
||||
|
||||
/**RNFirebase mimics the Web Firebase SDK Storage,
|
||||
* whilst providing some iOS and Android specific functionality.
|
||||
*/
|
||||
storage(): RNFirebase.storage.Storage;
|
||||
|
||||
/**
|
||||
* Firebase Cloud Messaging (FCM) allows you to send push messages at no cost to both Android & iOS platforms.
|
||||
* Assuming the installation instructions have been followed, FCM is ready to go.
|
||||
* As the Firebase Web SDK has limited messaging functionality,
|
||||
* the following methods within react-native-firebase have been created to handle FCM in the React Native environment.
|
||||
*/
|
||||
messaging(): RNFirebase.messaging.Messaging;
|
||||
|
||||
/**
|
||||
* RNFirebase provides crash reporting for your app out of the box.
|
||||
* Please note crashes do not appear in real-time on the console,
|
||||
* they tend to take a number of hours to appear
|
||||
* If you want to manually report a crash,
|
||||
* such as a pre-caught exception this is possible by using the report method.
|
||||
*/
|
||||
auth(): RNFirebase.auth.Auth;
|
||||
// config(): RNFirebase.config.Config;
|
||||
crash(): RNFirebase.crash.Crash;
|
||||
|
||||
static fabric: {
|
||||
crashlytics(): RNFirebase.crashlytics.Crashlytics;
|
||||
database(): RNFirebase.database.Database;
|
||||
fabric: {
|
||||
crashlytics(): RNFirebase.crashlytics.Crashlytics,
|
||||
};
|
||||
|
||||
apps: Array<string>;
|
||||
googleApiAvailability: RNFirebase.GoogleApiAvailabilityType;
|
||||
|
||||
static initializeApp(options?: any | RNFirebase.configurationOptions, name?: string): FireBase;
|
||||
|
||||
static app(name?: string): FireBase;
|
||||
|
||||
[key: string]: any;
|
||||
firestore(): RNFirebase.firestore.Firestore;
|
||||
links(): RNFirebase.links.Links;
|
||||
messaging(): RNFirebase.messaging.Messaging;
|
||||
// perf(): RNFirebase.perf.Performance;
|
||||
storage(): RNFirebase.storage.Storage;
|
||||
// utils(): RNFirebase.utils.Utils;
|
||||
readonly name: string;
|
||||
readonly options: Firebase.Options;
|
||||
}
|
||||
|
||||
namespace RNFirebase {
|
||||
export namespace RNFirebase {
|
||||
interface RnError extends Error {
|
||||
code?: string;
|
||||
}
|
||||
|
@ -476,6 +473,15 @@ declare module "react-native-firebase" {
|
|||
|
||||
update(values: Object, onComplete?: (a: RnError | null) => any): Promise<any>;
|
||||
}
|
||||
|
||||
interface DatabaseStatics {
|
||||
/** @see https://www.firebase.com/docs/java-api/javadoc/com/firebase/client/ServerValue.html#TIMESTAMP */
|
||||
ServerValue: {
|
||||
TIMESTAMP: {
|
||||
[key: string]: string
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -525,6 +531,37 @@ declare module "react-native-firebase" {
|
|||
[key: string]: any;
|
||||
}
|
||||
|
||||
type AdditionalUserInfo = {
|
||||
isNewUser: boolean,
|
||||
profile?: Object,
|
||||
providerId: string,
|
||||
username?: string,
|
||||
}
|
||||
|
||||
type UserCredential = {
|
||||
additionalUserInfo?: AdditionalUserInfo,
|
||||
user: User,
|
||||
}
|
||||
|
||||
type UserInfo = {
|
||||
displayName?: string,
|
||||
email?: string,
|
||||
phoneNumber?: string,
|
||||
photoURL?: string,
|
||||
providerId: string,
|
||||
uid: string,
|
||||
}
|
||||
|
||||
type UpdateProfile = {
|
||||
displayName?: string,
|
||||
photoURL?: string,
|
||||
}
|
||||
|
||||
type UserMetadata = {
|
||||
creationTime?: string,
|
||||
lastSignInTime?: string,
|
||||
}
|
||||
|
||||
interface User {
|
||||
/**
|
||||
* The user's display name (if available).
|
||||
|
@ -542,6 +579,10 @@ declare module "react-native-firebase" {
|
|||
*
|
||||
*/
|
||||
isAnonymous: boolean
|
||||
|
||||
metadata: UserMetadata
|
||||
|
||||
phoneNumber: string | null
|
||||
/**
|
||||
* - The URL of the user's profile picture (if available).
|
||||
*/
|
||||
|
@ -549,12 +590,12 @@ declare module "react-native-firebase" {
|
|||
/**
|
||||
* - Additional provider-specific information about the user.
|
||||
*/
|
||||
providerData: any | null
|
||||
providerData: Array<UserInfo>
|
||||
/**
|
||||
* - The authentication provider ID for the current user.
|
||||
* For example, 'facebook.com', or 'google.com'.
|
||||
*/
|
||||
providerId: string | null
|
||||
providerId: string
|
||||
/**
|
||||
* - The user's unique ID.
|
||||
*/
|
||||
|
@ -567,18 +608,26 @@ declare module "react-native-firebase" {
|
|||
|
||||
/**
|
||||
* Returns the users authentication token.
|
||||
*
|
||||
* @param forceRefresh: boolean - default to false
|
||||
*/
|
||||
getToken(): Promise<string>
|
||||
getIdToken(forceRefresh?: boolean): Promise<string>
|
||||
|
||||
/**
|
||||
* Reauthenticate the current user with credentials:
|
||||
*/
|
||||
reauthenticate(credential: Credential): Promise<void>
|
||||
getToken(forceRefresh?: boolean): Promise<string>
|
||||
|
||||
linkAndRetrieveDataWithCredential(credential: AuthCredential): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* Link the user with a 3rd party credential provider.
|
||||
*/
|
||||
linkWithCredential(credential: Credential): Promise<User>
|
||||
linkWithCredential(credential: AuthCredential): Promise<User>
|
||||
|
||||
reauthenticateAndRetrieveDataWithCredential(credential: AuthCredential): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* Re-authenticate a user with a third-party authentication provider
|
||||
*/
|
||||
reauthenticateWithCredential(credential: AuthCredential): Promise<void>
|
||||
|
||||
/**
|
||||
* Refreshes the current user.
|
||||
|
@ -589,7 +638,11 @@ declare module "react-native-firebase" {
|
|||
* Sends a verification email to a user.
|
||||
* This will Promise reject is the user is anonymous.
|
||||
*/
|
||||
sendEmailVerification(): Promise<void>
|
||||
sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise<void>
|
||||
|
||||
toJSON(): object
|
||||
|
||||
unlink(providerId: string): Promise<User>
|
||||
|
||||
/**
|
||||
* Updates the user's email address.
|
||||
|
@ -609,57 +662,114 @@ declare module "react-native-firebase" {
|
|||
* Updates a user's profile data.
|
||||
* Profile data should be an object of fields to update:
|
||||
*/
|
||||
updateProfile(profile: Object): Promise<void>
|
||||
updateProfile(updates: UpdateProfile): Promise<void>
|
||||
}
|
||||
|
||||
/** 3rd party provider Credentials */
|
||||
interface Credential {
|
||||
provider: string,
|
||||
token: string,
|
||||
secret: string
|
||||
type ActionCodeSettings = {
|
||||
android: {
|
||||
installApp?: boolean,
|
||||
minimumVersion?: string,
|
||||
packageName: string,
|
||||
},
|
||||
handleCodeInApp?: boolean,
|
||||
iOS: {
|
||||
bundleId?: string,
|
||||
},
|
||||
url: string,
|
||||
}
|
||||
|
||||
|
||||
interface ActionCodeInfo {
|
||||
email: string,
|
||||
error: string,
|
||||
fromEmail: string,
|
||||
verifyEmail: string,
|
||||
recoverEmail: string,
|
||||
passwordReset: string
|
||||
data: {
|
||||
email?: string,
|
||||
fromEmail?: string
|
||||
},
|
||||
operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL'
|
||||
}
|
||||
|
||||
interface ConfirmationResult {
|
||||
|
||||
confirm(verificationCode: string): Promise<User | null>;
|
||||
|
||||
verificationId: string | null;
|
||||
}
|
||||
|
||||
type PhoneAuthSnapshot = {
|
||||
state: 'sent' | 'timeout' | 'verified' | 'error',
|
||||
verificationId: string,
|
||||
code: string | null,
|
||||
error: Error | null,
|
||||
};
|
||||
|
||||
type PhoneAuthError = {
|
||||
code: string | null,
|
||||
verificationId: string,
|
||||
message: string | null,
|
||||
stack: string | null,
|
||||
};
|
||||
|
||||
interface PhoneAuthListener {
|
||||
|
||||
on(event: string,
|
||||
observer: () => PhoneAuthSnapshot,
|
||||
errorCb?: () => PhoneAuthError,
|
||||
successCb?: () => PhoneAuthSnapshot): PhoneAuthListener;
|
||||
|
||||
then(fn: () => PhoneAuthSnapshot): Promise<any>
|
||||
|
||||
catch(fn: () => Error): Promise<any>
|
||||
}
|
||||
|
||||
namespace auth {
|
||||
type AuthResult = {
|
||||
authenticated: boolean,
|
||||
user: object | null
|
||||
} | null;
|
||||
|
||||
type AuthProvider = {
|
||||
PROVIDER_ID: string,
|
||||
credential: (token: string, secret?: string) => AuthCredential,
|
||||
};
|
||||
|
||||
interface Auth {
|
||||
readonly app: App;
|
||||
/**
|
||||
* Returns the current Firebase authentication state.
|
||||
*/
|
||||
authenticated: boolean;
|
||||
authResult: AuthResult | null;
|
||||
/**
|
||||
* Returns the currently signed-in user (or null). See the User class documentation for further usage.
|
||||
*/
|
||||
currentUser: User | null
|
||||
|
||||
/**
|
||||
* Gets/Sets the language for the app instance
|
||||
*/
|
||||
languageCode: string | null;
|
||||
|
||||
/**
|
||||
* Listen for changes in the users auth state (logging in and out).
|
||||
* This method returns a unsubscribe function to stop listening to events.
|
||||
* Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use.
|
||||
*/
|
||||
onAuthStateChanged(nextOrObserver: Object, error?: (a: RnError) => any,
|
||||
completed?: () => any): () => any;
|
||||
onAuthStateChanged(listener: Function): () => void;
|
||||
|
||||
/**
|
||||
* We can create a user by calling the createUserWithEmailAndPassword() function.
|
||||
* The method accepts two parameters, an email and a password.
|
||||
* Listen for changes in id token.
|
||||
* This method returns a unsubscribe function to stop listening to events.
|
||||
* Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use.
|
||||
*/
|
||||
createUserWithEmailAndPassword(email: string, password: string): Promise<User>
|
||||
onIdTokenChanged(listener: Function): () => void;
|
||||
|
||||
/**
|
||||
* To sign a user in with their email and password, use the signInWithEmailAndPassword() function.
|
||||
* It accepts two parameters, the user's email and password:
|
||||
* Listen for changes in the user.
|
||||
* This method returns a unsubscribe function to stop listening to events.
|
||||
* Always ensure you unsubscribe from the listener when no longer needed to prevent updates to components no longer in use.
|
||||
*/
|
||||
signInWithEmailAndPassword(email: string, password: string): Promise<User>
|
||||
onUserChanged(listener: Function): () => void;
|
||||
|
||||
signOut(): Promise<void>
|
||||
|
||||
signInAnonymouslyAndRetrieveData(): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* Sign an anonymous user.
|
||||
|
@ -667,11 +777,23 @@ declare module "react-native-firebase" {
|
|||
*/
|
||||
signInAnonymously(): Promise<User>
|
||||
|
||||
createUserAndRetrieveDataWithEmailAndPassword(email: string, password: string): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* Sign in the user with a 3rd party credential provider.
|
||||
* credential requires the following properties:
|
||||
* We can create a user by calling the createUserWithEmailAndPassword() function.
|
||||
* The method accepts two parameters, an email and a password.
|
||||
*/
|
||||
signInWithCredential(credential: Credential): Promise<User>
|
||||
createUserWithEmailAndPassword(email: string, password: string): Promise<User>
|
||||
|
||||
signInAndRetrieveDataWithEmailAndPassword(email: string, password: string): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* To sign a user in with their email and password, use the signInWithEmailAndPassword() function.
|
||||
* It accepts two parameters, the user's email and password:
|
||||
*/
|
||||
signInWithEmailAndPassword(email: string, password: string): Promise<User>
|
||||
|
||||
signInAndRetrieveDataWithCustomToken(token: string): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* Sign a user in with a self-signed JWT token.
|
||||
|
@ -681,22 +803,42 @@ declare module "react-native-firebase" {
|
|||
*/
|
||||
signInWithCustomToken(token: string): Promise<User>
|
||||
|
||||
signInAndRetrieveDataWithCredential(credential: AuthCredential): Promise<UserCredential>
|
||||
|
||||
/**
|
||||
* Sign in the user with a 3rd party credential provider.
|
||||
* credential requires the following properties:
|
||||
*/
|
||||
signInWithCredential(credential: AuthCredential): Promise<User>
|
||||
|
||||
/**
|
||||
* Asynchronously signs in using a phone number.
|
||||
*/
|
||||
signInWithPhoneNumber(phoneNumber: string): Promise<ConfirmationResult>
|
||||
|
||||
/**
|
||||
* Returns a PhoneAuthListener to listen to phone verification events,
|
||||
* on the final completion event a PhoneAuthCredential can be generated for
|
||||
* authentication purposes.
|
||||
*/
|
||||
verifyPhoneNumber(phoneNumber: string, autoVerifyTimeout?: number): PhoneAuthListener
|
||||
|
||||
/**
|
||||
* Sends a password reset email to the given email address.
|
||||
* Unlike the web SDK,
|
||||
* the email will contain a password reset link rather than a code.
|
||||
*/
|
||||
sendPasswordResetEmail(email: string): Promise<void>
|
||||
sendPasswordResetEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise<void>
|
||||
|
||||
/**
|
||||
* Completes the password reset process, given a confirmation code and new password.
|
||||
*/
|
||||
confirmPasswordReset(code: string, newPassword: string): Promise<any>
|
||||
confirmPasswordReset(code: string, newPassword: string): Promise<void>
|
||||
|
||||
/**
|
||||
* Applies a verification code sent to the user by email or other out-of-band mechanism.
|
||||
*/
|
||||
applyActionCode(code: string): Promise<any>
|
||||
applyActionCode(code: string): Promise<void>
|
||||
|
||||
/**
|
||||
* Checks a verification code sent to the user by email or other out-of-band mechanism.
|
||||
|
@ -704,13 +846,30 @@ declare module "react-native-firebase" {
|
|||
checkActionCode(code: string): Promise<ActionCodeInfo>
|
||||
|
||||
/**
|
||||
* Completes the password reset process,
|
||||
* given a confirmation code and new password.
|
||||
* Returns a list of authentication providers that can be used to sign in a given user (identified by its main email address).
|
||||
*/
|
||||
signOut(): Promise<void>
|
||||
fetchProvidersForEmail(email: string): Promise<Array<string>>
|
||||
|
||||
verifyPasswordResetCode(code: string): Promise<string>
|
||||
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
interface AuthStatics {
|
||||
EmailAuthProvider: AuthProvider;
|
||||
PhoneAuthProvider: AuthProvider;
|
||||
GoogleAuthProvider: AuthProvider;
|
||||
GithubAuthProvider: AuthProvider;
|
||||
OAuthProvider: AuthProvider;
|
||||
TwitterAuthProvider: AuthProvider;
|
||||
FacebookAuthProvider: AuthProvider;
|
||||
PhoneAuthState: {
|
||||
CODE_SENT: string;
|
||||
AUTO_VERIFY_TIMEOUT: string;
|
||||
AUTO_VERIFIED: string;
|
||||
ERROR: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
namespace messaging {
|
||||
|
@ -895,5 +1054,315 @@ declare module "react-native-firebase" {
|
|||
setUserIdentifier(userId: string): void;
|
||||
}
|
||||
}
|
||||
|
||||
namespace links {
|
||||
interface Links {
|
||||
/** Creates a standard dynamic link. */
|
||||
createDynamicLink(parameters: LinkConfiguration): Promise<string>;
|
||||
/** Creates a short dynamic link. */
|
||||
createShortDynamicLink(parameters: LinkConfiguration): Promise<string>;
|
||||
/**
|
||||
* Returns the URL that the app has been launched from. If the app was
|
||||
* not launched from a URL the return value will be null.
|
||||
*/
|
||||
getInitialLink(): Promise<string | null>;
|
||||
/**
|
||||
* Subscribe to URL open events while the app is still running.
|
||||
* The listener is called from URL open events whilst the app is still
|
||||
* running, use getInitialLink for URLs which cause the app to open
|
||||
* from a previously closed / not running state.
|
||||
* Returns an unsubscribe function, call the returned function to
|
||||
* unsubscribe from all future events.
|
||||
*/
|
||||
onLink(listener: (url: string) => void): () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration when creating a Dynamic Link (standard or short). For
|
||||
* more information about each parameter, see the official Firebase docs:
|
||||
* https://firebase.google.com/docs/reference/dynamic-links/link-shortener
|
||||
*/
|
||||
interface LinkConfiguration {
|
||||
link: string,
|
||||
dynamicLinkDomain: string,
|
||||
androidInfo?: {
|
||||
androidLink?: string,
|
||||
androidPackageName: string,
|
||||
androidFallbackLink?: string,
|
||||
androidMinPackageVersionCode?: string,
|
||||
},
|
||||
iosInfo?: {
|
||||
iosBundleId: string,
|
||||
iosAppStoreId?: string,
|
||||
iosFallbackLink?: string,
|
||||
iosCustomScheme?: string,
|
||||
iosIpadBundleId?: string,
|
||||
iosIpadFallbackLink?: string,
|
||||
},
|
||||
socialMetaTagInfo?: {
|
||||
socialTitle: string,
|
||||
socialImageLink: string,
|
||||
socialDescription: string,
|
||||
},
|
||||
suffix?: {
|
||||
option: 'SHORT' | 'UNGUESSABLE',
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
namespace firestore {
|
||||
interface Firestore {
|
||||
readonly app: App;
|
||||
batch(): WriteBatch;
|
||||
collection(collectionPath: string): CollectionReference;
|
||||
doc(documentPath: string): DocumentReference;
|
||||
|
||||
/** NOT SUPPORTED YET */
|
||||
// enablePersistence(): Promise<void>;
|
||||
/** NOT SUPPORTED YET */
|
||||
// runTransaction(): Promise<any>;
|
||||
/** NOT SUPPORTED YET */
|
||||
// settings(): void;
|
||||
}
|
||||
|
||||
interface FirestoreStatics {
|
||||
FieldPath: typeof FieldPath;
|
||||
FieldValue: typeof FieldValue;
|
||||
GeoPoint: typeof GeoPoint;
|
||||
enableLogging(enabled: boolean): void;
|
||||
}
|
||||
|
||||
interface CollectionReference {
|
||||
readonly firestore: Firestore;
|
||||
readonly id: string;
|
||||
readonly parent: DocumentReference;
|
||||
add(data: object): Promise<DocumentReference>;
|
||||
doc(documentPath?: string): DocumentReference;
|
||||
endAt(snapshot: DocumentSnapshot): Query;
|
||||
endAt(...varargs: any[]): Query;
|
||||
endBefore(snapshot: DocumentSnapshot): Query;
|
||||
endBefore(...varargs: any[]): Query;
|
||||
get(): Promise<QuerySnapshot>;
|
||||
limit(limit: number): Query;
|
||||
onSnapshot(onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void;
|
||||
onSnapshot(observer: Query.Observer): () => void;
|
||||
onSnapshot(queryListenOptions: Query.QueryListenOptions, onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void;
|
||||
onSnapshot(queryListenOptions: Query.QueryListenOptions, observer: Query.Observer): () => void;
|
||||
orderBy(fieldPath: string | FieldPath, directionStr?: Types.QueryDirection): Query;
|
||||
startAfter(snapshot: DocumentSnapshot): Query;
|
||||
startAfter(...varargs: any[]): Query;
|
||||
startAt(snapshot: DocumentSnapshot): Query;
|
||||
startAt(...varargs: any[]): Query;
|
||||
where(fieldPath: string, op: Types.QueryOperator, value: any): Query;
|
||||
}
|
||||
|
||||
interface DocumentChange {
|
||||
readonly doc: DocumentSnapshot;
|
||||
readonly newIndex: number;
|
||||
readonly oldIndex: number;
|
||||
readonly type: string;
|
||||
}
|
||||
|
||||
interface DocumentReference {
|
||||
readonly firestore: Firestore;
|
||||
readonly id: string | null;
|
||||
readonly parent: CollectionReference;
|
||||
readonly path: string;
|
||||
collection(collectionPath: string): CollectionReference;
|
||||
delete(): Promise<void>;
|
||||
get(): Promise<DocumentSnapshot>;
|
||||
onSnapshot(onNext: DocumentReference.ObserverOnNext, onError?: DocumentReference.ObserverOnError): () => void;
|
||||
onSnapshot(observer: DocumentReference.Observer): () => void;
|
||||
onSnapshot(documentListenOptions: DocumentReference.DocumentListenOptions, onNext: DocumentReference.ObserverOnNext, onError?: DocumentReference.ObserverOnError): () => void;
|
||||
onSnapshot(documentListenOptions: DocumentReference.DocumentListenOptions, observer: DocumentReference.Observer): () => void;
|
||||
set(data: object, writeOptions?: Types.WriteOptions): Promise<void>;
|
||||
update(obj: object): Promise<void>;
|
||||
update(key1: Types.UpdateKey, val1: any): Promise<void>;
|
||||
update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any): Promise<void>;
|
||||
update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any): Promise<void>;
|
||||
update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any): Promise<void>;
|
||||
update(key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any, key5: Types.UpdateKey, val5: any): Promise<void>;
|
||||
}
|
||||
namespace DocumentReference {
|
||||
interface DocumentListenOptions {
|
||||
includeMetadataChanges: boolean;
|
||||
}
|
||||
|
||||
type ObserverOnNext = (documentSnapshot: DocumentSnapshot) => void;
|
||||
type ObserverOnError = (err: object) => void;
|
||||
interface Observer {
|
||||
next: ObserverOnNext;
|
||||
error?: ObserverOnError;
|
||||
}
|
||||
}
|
||||
|
||||
interface DocumentSnapshot {
|
||||
readonly exists: boolean;
|
||||
readonly id: string | null;
|
||||
readonly metadata: Types.SnapshotMetadata;
|
||||
readonly ref: DocumentReference;
|
||||
data(): object | void;
|
||||
get(fieldPath: string | FieldPath): any | undefined;
|
||||
}
|
||||
|
||||
class FieldPath {
|
||||
static documentId(): FieldPath;
|
||||
constructor(...segments: string[]);
|
||||
}
|
||||
|
||||
class FieldValue {
|
||||
static delete(): FieldValue;
|
||||
static serverTimestamp(): FieldValue;
|
||||
}
|
||||
|
||||
class GeoPoint {
|
||||
constructor(latitude: number, longitude: number);
|
||||
readonly latitude: number;
|
||||
readonly longitude: number;
|
||||
}
|
||||
|
||||
class Path {
|
||||
static fromName(name: string): Path;
|
||||
constructor(pathComponents: string[]);
|
||||
readonly id: string | null;
|
||||
readonly isDocument: boolean;
|
||||
readonly isCollection: boolean;
|
||||
readonly relativeName: string;
|
||||
child(relativePath: string): Path;
|
||||
parent(): Path | null;
|
||||
}
|
||||
|
||||
interface Query {
|
||||
readonly firestore: Firestore;
|
||||
endAt(snapshot: DocumentSnapshot): Query;
|
||||
endAt(...varargs: any[]): Query;
|
||||
endBefore(snapshot: DocumentSnapshot): Query;
|
||||
endBefore(...varargs: any[]): Query;
|
||||
get(): Promise<QuerySnapshot>;
|
||||
limit(limit: number): Query;
|
||||
onSnapshot(onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void;
|
||||
onSnapshot(observer: Query.Observer): () => void;
|
||||
onSnapshot(queryListenOptions: Query.QueryListenOptions, onNext: Query.ObserverOnNext, onError?: Query.ObserverOnError): () => void;
|
||||
onSnapshot(queryListenOptions: Query.QueryListenOptions, observer: Query.Observer): () => void;
|
||||
orderBy(fieldPath: string | FieldPath, directionStr?: Types.QueryDirection): Query;
|
||||
startAfter(snapshot: DocumentSnapshot): Query;
|
||||
startAfter(...varargs: any[]): Query;
|
||||
startAt(snapshot: DocumentSnapshot): Query;
|
||||
startAt(...varargs: any[]): Query;
|
||||
where(fieldPath: string, op: Types.QueryOperator, value: any): Query;
|
||||
}
|
||||
namespace Query {
|
||||
interface NativeFieldPath {
|
||||
elements?: string[];
|
||||
string?: string;
|
||||
type: 'fieldpath' | 'string';
|
||||
}
|
||||
|
||||
interface FieldFilter {
|
||||
fieldPath: NativeFieldPath;
|
||||
operator: string;
|
||||
value: any;
|
||||
}
|
||||
|
||||
interface FieldOrder {
|
||||
direction: string;
|
||||
fieldPath: NativeFieldPath;
|
||||
}
|
||||
|
||||
interface QueryOptions {
|
||||
endAt?: any[];
|
||||
endBefore?: any[];
|
||||
limit?: number;
|
||||
offset?: number;
|
||||
selectFields?: string[];
|
||||
startAfter?: any[];
|
||||
startAt?: any[];
|
||||
}
|
||||
|
||||
// The JS code expects at least one of 'includeDocumentMetadataChanges'
|
||||
// or 'includeQueryMetadataChanges' to be defined.
|
||||
interface _IncludeDocumentMetadataChanges {
|
||||
includeDocumentMetadataChanges: boolean;
|
||||
}
|
||||
interface _IncludeQueryMetadataChanges {
|
||||
includeQueryMetadataChanges: boolean;
|
||||
}
|
||||
type QueryListenOptions = _IncludeDocumentMetadataChanges | _IncludeQueryMetadataChanges | (_IncludeDocumentMetadataChanges & _IncludeQueryMetadataChanges);
|
||||
|
||||
type ObserverOnNext = (querySnapshot: QuerySnapshot) => void;
|
||||
type ObserverOnError = (err: object) => void;
|
||||
interface Observer {
|
||||
next: ObserverOnNext;
|
||||
error?: ObserverOnError;
|
||||
}
|
||||
}
|
||||
|
||||
interface QuerySnapshot {
|
||||
readonly docChanges: DocumentChange[];
|
||||
readonly docs: DocumentSnapshot[];
|
||||
readonly empty: boolean;
|
||||
readonly metadata: Types.SnapshotMetadata;
|
||||
readonly query: Query;
|
||||
readonly size: number;
|
||||
forEach(callback: (snapshot: DocumentSnapshot) => any): void;
|
||||
}
|
||||
namespace QuerySnapshot {
|
||||
interface NativeData {
|
||||
changes: Types.NativeDocumentChange[];
|
||||
documents: Types.NativeDocumentSnapshot[];
|
||||
metadata: Types.SnapshotMetadata;
|
||||
}
|
||||
}
|
||||
|
||||
interface WriteBatch {
|
||||
commit(): Promise<void>;
|
||||
delete(docRef: DocumentReference): WriteBatch;
|
||||
set(docRef: DocumentReference, data: object, options?: Types.WriteOptions): WriteBatch;
|
||||
// multiple overrides for update() to allow strong-typed var_args
|
||||
update(docRef: DocumentReference, obj: object): WriteBatch;
|
||||
update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any): WriteBatch;
|
||||
update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any): WriteBatch;
|
||||
update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any): WriteBatch;
|
||||
update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any): WriteBatch;
|
||||
update(docRef: DocumentReference, key1: Types.UpdateKey, val1: any, key2: Types.UpdateKey, val2: any, key3: Types.UpdateKey, val3: any, key4: Types.UpdateKey, val4: any, key5: Types.UpdateKey, val5: any): WriteBatch;
|
||||
}
|
||||
|
||||
namespace Types {
|
||||
interface NativeDocumentChange {
|
||||
document: NativeDocumentSnapshot;
|
||||
newIndex: number;
|
||||
oldIndex: number;
|
||||
type: string;
|
||||
}
|
||||
|
||||
interface NativeDocumentSnapshot {
|
||||
data: {
|
||||
[key: string]: TypeMap;
|
||||
};
|
||||
metadata: SnapshotMetadata;
|
||||
path: string;
|
||||
}
|
||||
|
||||
interface SnapshotMetadata {
|
||||
fromCache: boolean;
|
||||
hasPendingWrites: boolean;
|
||||
}
|
||||
|
||||
type QueryDirection = 'asc' | 'ASC' | 'desc' | 'DESC';
|
||||
type QueryOperator = '=' | '==' | '>' | '>=' | '<' | '<=';
|
||||
|
||||
interface TypeMap {
|
||||
type: 'array' | 'boolean' | 'date' | 'documentid' | 'fieldvalue' | 'geopoint' | 'null' | 'number' | 'object' | 'reference' | 'string';
|
||||
value: any;
|
||||
}
|
||||
|
||||
/** The key in update() function for DocumentReference and WriteBatch. */
|
||||
type UpdateKey = string | FieldPath
|
||||
|
||||
interface WriteOptions {
|
||||
merge?: boolean;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,13 +11,15 @@ const adMobPropTypes = {
|
|||
...ViewPropTypes,
|
||||
size: PropTypes.string.isRequired,
|
||||
unitId: PropTypes.string.isRequired,
|
||||
/* eslint-disable react/forbid-prop-types */
|
||||
request: PropTypes.object,
|
||||
video: PropTypes.object,
|
||||
/* eslint-enable react/forbid-prop-types */
|
||||
};
|
||||
Object.keys(EventTypes).forEach((eventType) => {
|
||||
Object.keys(EventTypes).forEach(eventType => {
|
||||
adMobPropTypes[eventType] = PropTypes.func;
|
||||
});
|
||||
Object.keys(NativeExpressEventTypes).forEach((eventType) => {
|
||||
Object.keys(NativeExpressEventTypes).forEach(eventType => {
|
||||
adMobPropTypes[eventType] = PropTypes.func;
|
||||
});
|
||||
|
||||
|
@ -67,7 +69,8 @@ class AdMobComponent extends React.Component {
|
|||
}
|
||||
}
|
||||
|
||||
if (nativeEvent.type === 'onSizeChange') this.updateSize(nativeEvent.payload);
|
||||
if (nativeEvent.type === 'onSizeChange')
|
||||
this.updateSize(nativeEvent.payload);
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export default class AdRequest {
|
||||
|
||||
constructor() {
|
||||
this._props = {
|
||||
keywords: [],
|
||||
|
@ -12,7 +11,7 @@ export default class AdRequest {
|
|||
}
|
||||
|
||||
addTestDevice(deviceId?: string) {
|
||||
this._props.testDevices.push(deviceId ? deviceId : 'DEVICE_ID_EMULATOR');
|
||||
this._props.testDevices.push(deviceId || 'DEVICE_ID_EMULATOR');
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,12 +2,7 @@ import React from 'react';
|
|||
import AdMobComponent from './AdMobComponent';
|
||||
|
||||
function Banner({ ...props }) {
|
||||
return (
|
||||
<AdMobComponent
|
||||
{...props}
|
||||
class={'RNFirebaseAdMobBanner'}
|
||||
/>
|
||||
);
|
||||
return <AdMobComponent {...props} class="RNFirebaseAdMobBanner" />;
|
||||
}
|
||||
|
||||
Banner.propTypes = AdMobComponent.propTypes;
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
export default {
|
||||
onAdLoaded: 'onAdLoaded',
|
||||
onAdOpened: 'onAdOpened',
|
||||
|
|
|
@ -1,19 +1,20 @@
|
|||
import { NativeModules, Platform } from 'react-native';
|
||||
import { Platform } from 'react-native';
|
||||
import { statics } from './';
|
||||
import AdRequest from './AdRequest';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
import { nativeToJSError } from '../../utils';
|
||||
|
||||
const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
|
||||
import type AdMob from './';
|
||||
|
||||
let subscriptions = [];
|
||||
|
||||
export default class Interstitial {
|
||||
_admob: AdMob;
|
||||
|
||||
constructor(admob: Object, adUnit: string) {
|
||||
constructor(admob: AdMob, adUnit: string) {
|
||||
// Interstitials on iOS require a new instance each time
|
||||
if (Platform.OS === 'ios') {
|
||||
FirebaseAdMob.clearInterstitial(adUnit);
|
||||
getNativeModule(admob).clearInterstitial(adUnit);
|
||||
}
|
||||
|
||||
for (let i = 0, len = subscriptions.length; i < len; i++) {
|
||||
|
@ -21,11 +22,14 @@ export default class Interstitial {
|
|||
}
|
||||
subscriptions = [];
|
||||
|
||||
this.admob = admob;
|
||||
this._admob = admob;
|
||||
this.adUnit = adUnit;
|
||||
this.loaded = false;
|
||||
SharedEventEmitter.removeAllListeners(`interstitial_${adUnit}`);
|
||||
SharedEventEmitter.addListener(`interstitial_${adUnit}`, this._onInterstitialEvent);
|
||||
SharedEventEmitter.addListener(
|
||||
`interstitial_${adUnit}`,
|
||||
this._onInterstitialEvent
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -33,7 +37,7 @@ export default class Interstitial {
|
|||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onInterstitialEvent = (event) => {
|
||||
_onInterstitialEvent = event => {
|
||||
const eventType = `interstitial:${this.adUnit}:${event.type}`;
|
||||
|
||||
let emitData = Object.assign({}, event);
|
||||
|
@ -65,7 +69,10 @@ export default class Interstitial {
|
|||
adRequest = new AdRequest().addTestDevice().build();
|
||||
}
|
||||
|
||||
return FirebaseAdMob.interstitialLoadAd(this.adUnit, adRequest);
|
||||
return getNativeModule(this._admob).interstitialLoadAd(
|
||||
this.adUnit,
|
||||
adRequest
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,7 +89,7 @@ export default class Interstitial {
|
|||
*/
|
||||
show() {
|
||||
if (this.loaded) {
|
||||
FirebaseAdMob.interstitialShowAd(this.adUnit);
|
||||
getNativeModule(this._admob).interstitialShowAd(this.adUnit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,11 +101,18 @@ export default class Interstitial {
|
|||
*/
|
||||
on(eventType, listenerCb) {
|
||||
if (!statics.EventTypes[eventType]) {
|
||||
console.warn(`Invalid event type provided, must be one of: ${Object.keys(statics.EventTypes).join(', ')}`);
|
||||
console.warn(
|
||||
`Invalid event type provided, must be one of: ${Object.keys(
|
||||
statics.EventTypes
|
||||
).join(', ')}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const sub = SharedEventEmitter.addListener(`interstitial:${this.adUnit}:${eventType}`, listenerCb);
|
||||
const sub = SharedEventEmitter.addListener(
|
||||
`interstitial:${this.adUnit}:${eventType}`,
|
||||
listenerCb
|
||||
);
|
||||
subscriptions.push(sub);
|
||||
return sub;
|
||||
}
|
||||
|
|
|
@ -2,12 +2,7 @@ import React from 'react';
|
|||
import AdMobComponent from './AdMobComponent';
|
||||
|
||||
function NativeExpress({ ...props }) {
|
||||
return (
|
||||
<AdMobComponent
|
||||
{...props}
|
||||
class={'RNFirebaseAdMobNativeExpress'}
|
||||
/>
|
||||
);
|
||||
return <AdMobComponent {...props} class="RNFirebaseAdMobNativeExpress" />;
|
||||
}
|
||||
|
||||
NativeExpress.propTypes = AdMobComponent.propTypes;
|
||||
|
|
|
@ -1,26 +1,29 @@
|
|||
import { NativeModules } from 'react-native';
|
||||
import { statics } from './';
|
||||
import AdRequest from './AdRequest';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
import { nativeToJSError } from '../../utils';
|
||||
|
||||
const FirebaseAdMob = NativeModules.RNFirebaseAdMob;
|
||||
import type AdMob from './';
|
||||
|
||||
let subscriptions = [];
|
||||
|
||||
export default class RewardedVideo {
|
||||
_admob: AdMob;
|
||||
|
||||
constructor(admob: Object, adUnit: string) {
|
||||
constructor(admob: AdMob, adUnit: string) {
|
||||
for (let i = 0, len = subscriptions.length; i < len; i++) {
|
||||
subscriptions[i].remove();
|
||||
}
|
||||
subscriptions = [];
|
||||
|
||||
this.admob = admob;
|
||||
this._admob = admob;
|
||||
this.adUnit = adUnit;
|
||||
this.loaded = false;
|
||||
SharedEventEmitter.removeAllListeners(`rewarded_video_${adUnit}`);
|
||||
SharedEventEmitter.addListener(`rewarded_video_${adUnit}`, this._onRewardedVideoEvent);
|
||||
SharedEventEmitter.addListener(
|
||||
`rewarded_video_${adUnit}`,
|
||||
this._onRewardedVideoEvent
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,7 +31,7 @@ export default class RewardedVideo {
|
|||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onRewardedVideoEvent = (event) => {
|
||||
_onRewardedVideoEvent = event => {
|
||||
const eventType = `rewarded_video:${this.adUnit}:${event.type}`;
|
||||
|
||||
let emitData = Object.assign({}, event);
|
||||
|
@ -60,7 +63,10 @@ export default class RewardedVideo {
|
|||
adRequest = new AdRequest().addTestDevice().build();
|
||||
}
|
||||
|
||||
return FirebaseAdMob.rewardedVideoLoadAd(this.adUnit, adRequest);
|
||||
return getNativeModule(this._admob).rewardedVideoLoadAd(
|
||||
this.adUnit,
|
||||
adRequest
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -77,7 +83,7 @@ export default class RewardedVideo {
|
|||
*/
|
||||
show() {
|
||||
if (this.loaded) {
|
||||
FirebaseAdMob.rewardedVideoShowAd(this.adUnit);
|
||||
getNativeModule(this._admob).rewardedVideoShowAd(this.adUnit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,11 +100,18 @@ export default class RewardedVideo {
|
|||
};
|
||||
|
||||
if (!types[eventType]) {
|
||||
console.warn(`Invalid event type provided, must be one of: ${Object.keys(types).join(', ')}`);
|
||||
console.warn(
|
||||
`Invalid event type provided, must be one of: ${Object.keys(types).join(
|
||||
', '
|
||||
)}`
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
const sub = SharedEventEmitter.addListener(`rewarded_video:${this.adUnit}:${eventType}`, listenerCb);
|
||||
const sub = SharedEventEmitter.addListener(
|
||||
`rewarded_video:${this.adUnit}:${eventType}`,
|
||||
listenerCb
|
||||
);
|
||||
subscriptions.push(sub);
|
||||
return sub;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
export default class VideoOptions {
|
||||
|
||||
constructor() {
|
||||
this._props = {
|
||||
startMuted: true,
|
||||
|
|
|
@ -25,14 +25,11 @@ type NativeEvent = {
|
|||
adUnit: string,
|
||||
payload: Object,
|
||||
type: string,
|
||||
}
|
||||
};
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
'interstitial_event',
|
||||
'rewarded_video_event',
|
||||
];
|
||||
const NATIVE_EVENTS = ['interstitial_event', 'rewarded_video_event'];
|
||||
|
||||
export const MODULE_NAME = 'RNFirebaseAdmob';
|
||||
export const MODULE_NAME = 'RNFirebaseAdMob';
|
||||
export const NAMESPACE = 'admob';
|
||||
|
||||
export default class AdMob extends ModuleBase {
|
||||
|
@ -43,21 +40,28 @@ export default class AdMob extends ModuleBase {
|
|||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
|
||||
this._initialized = false;
|
||||
this._appId = null;
|
||||
|
||||
SharedEventEmitter.addListener('interstitial_event', this._onInterstitialEvent.bind(this));
|
||||
SharedEventEmitter.addListener('rewarded_video_event', this._onRewardedVideoEvent.bind(this));
|
||||
SharedEventEmitter.addListener(
|
||||
'interstitial_event',
|
||||
this._onInterstitialEvent.bind(this)
|
||||
);
|
||||
SharedEventEmitter.addListener(
|
||||
'rewarded_video_event',
|
||||
this._onRewardedVideoEvent.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
_onInterstitialEvent(event: NativeEvent): void {
|
||||
const { adUnit } = event;
|
||||
const jsEventType = `interstitial_${adUnit}`;
|
||||
|
||||
if (!SharedEventEmitter.hasListeners(jsEventType)) {
|
||||
if (SharedEventEmitter.listeners(jsEventType).length === 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
@ -68,7 +72,7 @@ export default class AdMob extends ModuleBase {
|
|||
const { adUnit } = event;
|
||||
const jsEventType = `rewarded_video_${adUnit}`;
|
||||
|
||||
if (!SharedEventEmitter.hasListeners(jsEventType)) {
|
||||
if (SharedEventEmitter.listeners(jsEventType).length === 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
|
@ -87,7 +91,9 @@ export default class AdMob extends ModuleBase {
|
|||
|
||||
openDebugMenu(): void {
|
||||
if (!this._initialized) {
|
||||
getLogger(this).warn('AdMob needs to be initialized before opening the dev menu!');
|
||||
getLogger(this).warn(
|
||||
'AdMob needs to be initialized before opening the dev menu!'
|
||||
);
|
||||
} else {
|
||||
getLogger(this).info('Opening debug menu');
|
||||
getNativeModule(this).openDebugMenu(this._appId);
|
||||
|
|
|
@ -32,6 +32,7 @@ export default class Analytics extends ModuleBase {
|
|||
constructor(app: App) {
|
||||
super(app, {
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
@ -45,16 +46,21 @@ export default class Analytics extends ModuleBase {
|
|||
logEvent(name: string, params: Object = {}): void {
|
||||
// check name is not a reserved event name
|
||||
if (ReservedEventNames.includes(name)) {
|
||||
throw new Error(`event name '${name}' is a reserved event name and can not be used.`);
|
||||
throw new Error(
|
||||
`event name '${name}' is a reserved event name and can not be used.`
|
||||
);
|
||||
}
|
||||
|
||||
// name format validation
|
||||
if (!AlphaNumericUnderscore.test(name)) {
|
||||
throw new Error(`Event name '${name}' is invalid. Names should contain 1 to 32 alphanumeric characters or underscores.`);
|
||||
throw new Error(
|
||||
`Event name '${name}' is invalid. Names should contain 1 to 32 alphanumeric characters or underscores.`
|
||||
);
|
||||
}
|
||||
|
||||
// maximum number of allowed params check
|
||||
if (params && Object.keys(params).length > 25) throw new Error('Maximum number of parameters exceeded (25).');
|
||||
if (params && Object.keys(params).length > 25)
|
||||
throw new Error('Maximum number of parameters exceeded (25).');
|
||||
|
||||
// Parameter names can be up to 24 characters long and must start with an alphabetic character
|
||||
// and contain only alphanumeric characters and underscores. Only String, long and double param
|
||||
|
@ -120,9 +126,9 @@ export default class Analytics extends ModuleBase {
|
|||
* @param object
|
||||
*/
|
||||
setUserProperties(object: Object): void {
|
||||
for (const property of Object.keys(object)) {
|
||||
Object.keys(object).forEach(property => {
|
||||
getNativeModule(this).setUserProperty(property, object[property]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,10 @@ export default class ConfirmationResult {
|
|||
* @param verificationCode
|
||||
* @return {*}
|
||||
*/
|
||||
confirm(verificationCode: string): Promise<?User> {
|
||||
return this._auth._interceptUserValue(getNativeModule(this._auth)._confirmVerificationCode(verificationCode));
|
||||
confirm(verificationCode: string): Promise<User> {
|
||||
return getNativeModule(this._auth)
|
||||
._confirmVerificationCode(verificationCode)
|
||||
.then(user => this._auth._setUser(user));
|
||||
}
|
||||
|
||||
get verificationId(): string | null {
|
||||
|
|
|
@ -1,7 +1,14 @@
|
|||
// @flow
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import { SharedEventEmitter } from '../../utils/events';
|
||||
import { generatePushID, isFunction, isAndroid, isIOS, isString, nativeToJSError } from '../../utils';
|
||||
import {
|
||||
generatePushID,
|
||||
isFunction,
|
||||
isAndroid,
|
||||
isIOS,
|
||||
isString,
|
||||
nativeToJSError,
|
||||
} from '../../utils';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
|
||||
import type Auth from './';
|
||||
|
@ -50,9 +57,15 @@ export default class PhoneAuthListener {
|
|||
// internal events
|
||||
this._internalEvents = {
|
||||
codeSent: `phone:auth:${this._phoneAuthRequestKey}:onCodeSent`,
|
||||
verificationFailed: `phone:auth:${this._phoneAuthRequestKey}:onVerificationFailed`,
|
||||
verificationComplete: `phone:auth:${this._phoneAuthRequestKey}:onVerificationComplete`,
|
||||
codeAutoRetrievalTimeout: `phone:auth:${this._phoneAuthRequestKey}:onCodeAutoRetrievalTimeout`,
|
||||
verificationFailed: `phone:auth:${
|
||||
this._phoneAuthRequestKey
|
||||
}:onVerificationFailed`,
|
||||
verificationComplete: `phone:auth:${
|
||||
this._phoneAuthRequestKey
|
||||
}:onVerificationComplete`,
|
||||
codeAutoRetrievalTimeout: `phone:auth:${
|
||||
this._phoneAuthRequestKey
|
||||
}:onCodeAutoRetrievalTimeout`,
|
||||
};
|
||||
|
||||
// user observer events
|
||||
|
@ -73,14 +86,14 @@ export default class PhoneAuthListener {
|
|||
getNativeModule(this._auth).verifyPhoneNumber(
|
||||
phoneNumber,
|
||||
this._phoneAuthRequestKey,
|
||||
this._timeout,
|
||||
this._timeout
|
||||
);
|
||||
}
|
||||
|
||||
if (isIOS) {
|
||||
getNativeModule(this._auth).verifyPhoneNumber(
|
||||
phoneNumber,
|
||||
this._phoneAuthRequestKey,
|
||||
this._phoneAuthRequestKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -94,8 +107,11 @@ export default class PhoneAuthListener {
|
|||
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
const type = events[i];
|
||||
SharedEventEmitter.once(
|
||||
this._internalEvents[type],
|
||||
// $FlowBug: Flow doesn't support indexable signatures on classes: https://github.com/facebook/flow/issues/1323
|
||||
SharedEventEmitter.once(this._internalEvents[type], this[`_${type}Handler`].bind(this));
|
||||
this[`_${type}Handler`].bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -143,14 +159,15 @@ export default class PhoneAuthListener {
|
|||
* @private
|
||||
*/
|
||||
_removeAllListeners() {
|
||||
setTimeout(() => { // move to next event loop - not sure if needed
|
||||
setTimeout(() => {
|
||||
// move to next event loop - not sure if needed
|
||||
// internal listeners
|
||||
Object.values(this._internalEvents).forEach((event) => {
|
||||
Object.values(this._internalEvents).forEach(event => {
|
||||
SharedEventEmitter.removeAllListeners(event);
|
||||
});
|
||||
|
||||
// user observer listeners
|
||||
Object.values(this._publicEvents).forEach((publicEvent) => {
|
||||
Object.values(this._publicEvents).forEach(publicEvent => {
|
||||
SharedEventEmitter.removeAllListeners(publicEvent);
|
||||
});
|
||||
}, 0);
|
||||
|
@ -163,12 +180,12 @@ export default class PhoneAuthListener {
|
|||
_promiseDeferred() {
|
||||
if (!this._promise) {
|
||||
this._promise = new Promise((resolve, reject) => {
|
||||
this._resolve = (result) => {
|
||||
this._resolve = result => {
|
||||
this._resolve = null;
|
||||
return resolve(result);
|
||||
};
|
||||
|
||||
this._reject = (possibleError) => {
|
||||
this._reject = possibleError => {
|
||||
this._reject = null;
|
||||
return reject(possibleError);
|
||||
};
|
||||
|
@ -261,22 +278,36 @@ export default class PhoneAuthListener {
|
|||
this._removeAllListeners();
|
||||
}
|
||||
|
||||
|
||||
/* -------------
|
||||
-- PUBLIC API
|
||||
--------------*/
|
||||
|
||||
on(event: string, observer: () => PhoneAuthSnapshot, errorCb?: () => PhoneAuthError, successCb?: () => PhoneAuthSnapshot): this {
|
||||
on(
|
||||
event: string,
|
||||
observer: () => PhoneAuthSnapshot,
|
||||
errorCb?: () => PhoneAuthError,
|
||||
successCb?: () => PhoneAuthSnapshot
|
||||
): this {
|
||||
if (!isString(event)) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('event', 'string', 'on'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('event', 'string', 'on')
|
||||
);
|
||||
}
|
||||
|
||||
if (event !== 'state_changed') {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_ARG_INVALID_VALUE('event', 'state_changed', event));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_ARG_INVALID_VALUE(
|
||||
'event',
|
||||
'state_changed',
|
||||
event
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!isFunction(observer)) {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('observer', 'function', 'on'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_MISSING_ARG_NAMED('observer', 'function', 'on')
|
||||
);
|
||||
}
|
||||
|
||||
this._addUserObserver(observer);
|
||||
|
|
|
@ -6,19 +6,13 @@ import INTERNALS from '../../utils/internals';
|
|||
import { getNativeModule } from '../../utils/native';
|
||||
|
||||
import type Auth from './';
|
||||
import type { ActionCodeSettings, AuthCredential } from '../../types';
|
||||
|
||||
type NativeUser = {
|
||||
displayName?: string,
|
||||
email?: string,
|
||||
emailVerified?: boolean,
|
||||
isAnonymous?: boolean,
|
||||
phoneNumber?: string,
|
||||
photoURL?: string,
|
||||
providerData: UserInfo[],
|
||||
providerId: string,
|
||||
uid: string,
|
||||
}
|
||||
import type {
|
||||
ActionCodeSettings,
|
||||
AuthCredential,
|
||||
NativeUser,
|
||||
UserCredential,
|
||||
UserMetadata,
|
||||
} from './types';
|
||||
|
||||
type UserInfo = {
|
||||
displayName?: string,
|
||||
|
@ -27,7 +21,12 @@ type UserInfo = {
|
|||
photoURL?: string,
|
||||
providerId: string,
|
||||
uid: string,
|
||||
}
|
||||
};
|
||||
|
||||
type UpdateProfile = {
|
||||
displayName?: string,
|
||||
photoURL?: string,
|
||||
};
|
||||
|
||||
export default class User {
|
||||
_auth: Auth;
|
||||
|
@ -63,6 +62,10 @@ export default class User {
|
|||
return this._user.isAnonymous || false;
|
||||
}
|
||||
|
||||
get metadata(): UserMetadata {
|
||||
return this._user.metadata;
|
||||
}
|
||||
|
||||
get phoneNumber(): ?string {
|
||||
return this._user.phoneNumber || null;
|
||||
}
|
||||
|
@ -92,8 +95,11 @@ export default class User {
|
|||
* @return {Promise}
|
||||
*/
|
||||
delete(): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).delete());
|
||||
return getNativeModule(this._auth)
|
||||
.delete()
|
||||
.then(() => {
|
||||
this._auth._setUser();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -105,12 +111,48 @@ export default class User {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* get the token of current user
|
||||
* @deprecated Deprecated getToken in favor of getIdToken.
|
||||
* @return {Promise}
|
||||
*/
|
||||
getToken(forceRefresh: boolean = false): Promise<Object> {
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.getToken in favor of firebase.User.prototype.getIdToken.'
|
||||
);
|
||||
return getNativeModule(this._auth).getToken(forceRefresh);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Deprecated linkWithCredential in favor of linkAndRetrieveDataWithCredential.
|
||||
* @param credential
|
||||
*/
|
||||
linkWithCredential(credential: AuthCredential): Promise<User> {
|
||||
return this._auth
|
||||
._interceptUserValue(getNativeModule(this._auth).link(credential.providerId, credential.token, credential.secret));
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.linkWithCredential in favor of firebase.User.prototype.linkAndRetrieveDataWithCredential.'
|
||||
);
|
||||
return getNativeModule(this._auth)
|
||||
.linkWithCredential(
|
||||
credential.providerId,
|
||||
credential.token,
|
||||
credential.secret
|
||||
)
|
||||
.then(user => this._auth._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param credential
|
||||
*/
|
||||
linkAndRetrieveDataWithCredential(
|
||||
credential: AuthCredential
|
||||
): Promise<UserCredential> {
|
||||
return getNativeModule(this._auth)
|
||||
.linkAndRetrieveDataWithCredential(
|
||||
credential.providerId,
|
||||
credential.token,
|
||||
credential.secret
|
||||
)
|
||||
.then(userCredential => this._auth._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -118,8 +160,34 @@ export default class User {
|
|||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
reauthenticateWithCredential(credential: AuthCredential): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).reauthenticate(credential.providerId, credential.token, credential.secret));
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.reauthenticateWithCredential in favor of firebase.User.prototype.reauthenticateAndRetrieveDataWithCredential.'
|
||||
);
|
||||
return getNativeModule(this._auth)
|
||||
.reauthenticateWithCredential(
|
||||
credential.providerId,
|
||||
credential.token,
|
||||
credential.secret
|
||||
)
|
||||
.then(user => {
|
||||
this._auth._setUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-authenticate a user with a third-party authentication provider
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
reauthenticateAndRetrieveDataWithCredential(
|
||||
credential: AuthCredential
|
||||
): Promise<UserCredential> {
|
||||
return getNativeModule(this._auth)
|
||||
.reauthenticateAndRetrieveDataWithCredential(
|
||||
credential.providerId,
|
||||
credential.token,
|
||||
credential.secret
|
||||
)
|
||||
.then(userCredential => this._auth._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -127,16 +195,24 @@ export default class User {
|
|||
* @return {Promise}
|
||||
*/
|
||||
reload(): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).reload());
|
||||
return getNativeModule(this._auth)
|
||||
.reload()
|
||||
.then(user => {
|
||||
this._auth._setUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Send verification email to current user.
|
||||
*/
|
||||
sendEmailVerification(actionCodeSettings?: ActionCodeSettings): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).sendEmailVerification(actionCodeSettings));
|
||||
sendEmailVerification(
|
||||
actionCodeSettings?: ActionCodeSettings
|
||||
): Promise<void> {
|
||||
return getNativeModule(this._auth)
|
||||
.sendEmailVerification(actionCodeSettings)
|
||||
.then(user => {
|
||||
this._auth._setUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
toJSON(): Object {
|
||||
|
@ -149,7 +225,9 @@ export default class User {
|
|||
* @return {Promise.<TResult>|*}
|
||||
*/
|
||||
unlink(providerId: string): Promise<User> {
|
||||
return this._auth._interceptUserValue(getNativeModule(this._auth).unlink(providerId));
|
||||
return getNativeModule(this._auth)
|
||||
.unlink(providerId)
|
||||
.then(user => this._auth._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,8 +237,11 @@ export default class User {
|
|||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
updateEmail(email: string): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).updateEmail(email));
|
||||
return getNativeModule(this._auth)
|
||||
.updateEmail(email)
|
||||
.then(user => {
|
||||
this._auth._setUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -169,8 +250,11 @@ export default class User {
|
|||
* @return {Promise}
|
||||
*/
|
||||
updatePassword(password: string): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).updatePassword(password));
|
||||
return getNativeModule(this._auth)
|
||||
.updatePassword(password)
|
||||
.then(user => {
|
||||
this._auth._setUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -178,58 +262,81 @@ export default class User {
|
|||
* @param {Object} updates An object containing the keys listed [here](https://firebase.google.com/docs/auth/ios/manage-users#update_a_users_profile)
|
||||
* @return {Promise}
|
||||
*/
|
||||
updateProfile(updates: Object = {}): Promise<void> {
|
||||
return this._auth
|
||||
._interceptUndefinedUserValue(getNativeModule(this._auth).updateProfile(updates));
|
||||
}
|
||||
|
||||
/**
|
||||
* get the token of current user
|
||||
* @deprecated Deprecated getToken in favor of getIdToken.
|
||||
* @return {Promise}
|
||||
*/
|
||||
getToken(forceRefresh: boolean = false): Promise<Object> {
|
||||
console.warn('Deprecated firebase.User.prototype.getToken in favor of firebase.User.prototype.getIdToken.');
|
||||
return getNativeModule(this._auth).getToken(forceRefresh);
|
||||
updateProfile(updates: UpdateProfile = {}): Promise<void> {
|
||||
return getNativeModule(this._auth)
|
||||
.updateProfile(updates)
|
||||
.then(user => {
|
||||
this._auth._setUser(user);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* KNOWN UNSUPPORTED METHODS
|
||||
*/
|
||||
|
||||
linkAndRetrieveDataWithCredential() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'linkAndRetrieveDataWithCredential'));
|
||||
}
|
||||
|
||||
linkWithPhoneNumber() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'linkWithPhoneNumber'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
|
||||
'User',
|
||||
'linkWithPhoneNumber'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
linkWithPopup() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'linkWithPopup'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'linkWithPopup')
|
||||
);
|
||||
}
|
||||
|
||||
linkWithRedirect() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'linkWithRedirect'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
|
||||
'User',
|
||||
'linkWithRedirect'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
reauthenticateWithPhoneNumber() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'reauthenticateWithPhoneNumber'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
|
||||
'User',
|
||||
'reauthenticateWithPhoneNumber'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
reauthenticateWithPopup() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'reauthenticateWithPopup'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
|
||||
'User',
|
||||
'reauthenticateWithPopup'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
reauthenticateWithRedirect() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'reauthenticateWithRedirect'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
|
||||
'User',
|
||||
'reauthenticateWithRedirect'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
updatePhoneNumber() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('User', 'updatePhoneNumber'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD(
|
||||
'User',
|
||||
'updatePhoneNumber'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
get refreshToken(): string {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('User', 'refreshToken'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_PROPERTY('User', 'refreshToken')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,21 +15,36 @@ import EmailAuthProvider from './providers/EmailAuthProvider';
|
|||
import PhoneAuthProvider from './providers/PhoneAuthProvider';
|
||||
import GoogleAuthProvider from './providers/GoogleAuthProvider';
|
||||
import GithubAuthProvider from './providers/GithubAuthProvider';
|
||||
import OAuthProvider from './providers/OAuthProvider';
|
||||
import TwitterAuthProvider from './providers/TwitterAuthProvider';
|
||||
import FacebookAuthProvider from './providers/FacebookAuthProvider';
|
||||
|
||||
import PhoneAuthListener from './PhoneAuthListener';
|
||||
|
||||
import type { ActionCodeSettings, AuthCredential } from '../../types';
|
||||
import type {
|
||||
ActionCodeSettings,
|
||||
AuthCredential,
|
||||
NativeUser,
|
||||
NativeUserCredential,
|
||||
UserCredential,
|
||||
} from './types';
|
||||
import type App from '../core/firebase-app';
|
||||
|
||||
type AuthResult = {
|
||||
authenticated: boolean,
|
||||
user: Object|null
|
||||
} | null;
|
||||
type AuthState = {
|
||||
user?: NativeUser,
|
||||
};
|
||||
|
||||
type ActionCodeInfo = {
|
||||
data: {
|
||||
email?: string,
|
||||
fromEmail?: string,
|
||||
},
|
||||
operation: 'PASSWORD_RESET' | 'VERIFY_EMAIL' | 'RECOVER_EMAIL',
|
||||
};
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
'auth_state_changed',
|
||||
'auth_id_token_changed',
|
||||
'phone_auth_state_changed',
|
||||
];
|
||||
|
||||
|
@ -37,99 +52,79 @@ export const MODULE_NAME = 'RNFirebaseAuth';
|
|||
export const NAMESPACE = 'auth';
|
||||
|
||||
export default class Auth extends ModuleBase {
|
||||
_authResult: AuthResult | null;
|
||||
_authResult: boolean;
|
||||
_languageCode: string;
|
||||
_user: User | null;
|
||||
|
||||
constructor(app: App) {
|
||||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: true,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
this._user = null;
|
||||
this._authResult = null;
|
||||
this._authResult = false;
|
||||
this._languageCode =
|
||||
getNativeModule(this).APP_LANGUAGE[app._name] ||
|
||||
getNativeModule(this).APP_LANGUAGE['[DEFAULT]'];
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onAuthStateChanged
|
||||
getAppEventName(this, 'auth_state_changed'),
|
||||
this._onInternalAuthStateChanged.bind(this),
|
||||
(state: AuthState) => {
|
||||
this._setUser(state.user);
|
||||
SharedEventEmitter.emit(
|
||||
getAppEventName(this, 'onAuthStateChanged'),
|
||||
this._user
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public events based on event.type
|
||||
getAppEventName(this, 'phone_auth_state_changed'),
|
||||
this._onInternalPhoneAuthStateChanged.bind(this),
|
||||
(event: Object) => {
|
||||
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
|
||||
SharedEventEmitter.emit(eventKey, event.state);
|
||||
}
|
||||
);
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onIdTokenChanged
|
||||
getAppEventName(this, 'auth_id_token_changed'),
|
||||
this._onInternalIdTokenChanged.bind(this),
|
||||
(auth: AuthState) => {
|
||||
this._setUser(auth.user);
|
||||
SharedEventEmitter.emit(
|
||||
getAppEventName(this, 'onIdTokenChanged'),
|
||||
this._user
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
getNativeModule(this).addAuthStateListener();
|
||||
getNativeModule(this).addIdTokenListener();
|
||||
}
|
||||
|
||||
/**
|
||||
* Route a phone state change event to the correct listeners
|
||||
* @param event
|
||||
* @private
|
||||
*/
|
||||
_onInternalPhoneAuthStateChanged(event: Object) {
|
||||
const eventKey = `phone:auth:${event.requestKey}:${event.type}`;
|
||||
SharedEventEmitter.emit(eventKey, event.state);
|
||||
}
|
||||
|
||||
_setAuthState(auth: AuthResult) {
|
||||
this._authResult = auth;
|
||||
this._user = auth && auth.user ? new User(this, auth.user) : null;
|
||||
_setUser(user: ?NativeUser): ?User {
|
||||
this._authResult = true;
|
||||
this._user = user ? new User(this, user) : null;
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onUserChanged'), this._user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal auth changed listener
|
||||
* @param auth
|
||||
* @private
|
||||
*/
|
||||
_onInternalAuthStateChanged(auth: AuthResult) {
|
||||
this._setAuthState(auth);
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onAuthStateChanged'), this._user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal auth changed listener
|
||||
* @param auth
|
||||
* @param emit
|
||||
* @private
|
||||
*/
|
||||
_onInternalIdTokenChanged(auth: AuthResult) {
|
||||
this._setAuthState(auth);
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onIdTokenChanged'), this._user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercept all user actions and send their results to
|
||||
* auth state change before resolving
|
||||
* @param promise
|
||||
* @returns {Promise.<*>}
|
||||
* @private
|
||||
*/
|
||||
_interceptUserValue(promise: Promise<AuthResult>): Promise<User> {
|
||||
return promise.then((result: AuthResult) => {
|
||||
if (!result) this._setAuthState(null);
|
||||
else if (result.user) this._setAuthState(result);
|
||||
else if (result.uid) this._setAuthState({ authenticated: true, user: result });
|
||||
return this._user;
|
||||
});
|
||||
}
|
||||
|
||||
_interceptUndefinedUserValue(promise: Promise<AuthResult>): Promise<void> {
|
||||
return this._interceptUserValue(promise)
|
||||
.then(() => {});
|
||||
_setUserCredential(userCredential: NativeUserCredential): UserCredential {
|
||||
const user = new User(this, userCredential.user);
|
||||
this._authResult = true;
|
||||
this._user = user;
|
||||
SharedEventEmitter.emit(getAppEventName(this, 'onUserChanged'), this._user);
|
||||
return {
|
||||
additionalUserInfo: userCredential.additionalUserInfo,
|
||||
user,
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -142,18 +137,19 @@ export default class Auth extends ModuleBase {
|
|||
*/
|
||||
onAuthStateChanged(listener: Function) {
|
||||
getLogger(this).info('Creating onAuthStateChanged listener');
|
||||
SharedEventEmitter.addListener(getAppEventName(this, 'onAuthStateChanged'), listener);
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'onAuthStateChanged'),
|
||||
listener
|
||||
);
|
||||
if (this._authResult) listener(this._user || null);
|
||||
return this._offAuthStateChanged.bind(this, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove auth change listener
|
||||
* @param listener
|
||||
*/
|
||||
_offAuthStateChanged(listener: Function) {
|
||||
return () => {
|
||||
getLogger(this).info('Removing onAuthStateChanged listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this, 'onAuthStateChanged'), listener);
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this, 'onAuthStateChanged'),
|
||||
listener
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -162,18 +158,19 @@ export default class Auth extends ModuleBase {
|
|||
*/
|
||||
onIdTokenChanged(listener: Function) {
|
||||
getLogger(this).info('Creating onIdTokenChanged listener');
|
||||
SharedEventEmitter.addListener(getAppEventName(this, 'onIdTokenChanged'), listener);
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'onIdTokenChanged'),
|
||||
listener
|
||||
);
|
||||
if (this._authResult) listener(this._user || null);
|
||||
return this._offIdTokenChanged.bind(this, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove id token change listener
|
||||
* @param listener
|
||||
*/
|
||||
_offIdTokenChanged(listener: Function) {
|
||||
return () => {
|
||||
getLogger(this).info('Removing onIdTokenChanged listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this, 'onIdTokenChanged'), listener);
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this, 'onIdTokenChanged'),
|
||||
listener
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,18 +179,19 @@ export default class Auth extends ModuleBase {
|
|||
*/
|
||||
onUserChanged(listener: Function) {
|
||||
getLogger(this).info('Creating onUserChanged listener');
|
||||
SharedEventEmitter.addListener(getAppEventName(this, 'onUserChanged'), listener);
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'onUserChanged'),
|
||||
listener
|
||||
);
|
||||
if (this._authResult) listener(this._user || null);
|
||||
return this._offUserChanged.bind(this, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove user change listener
|
||||
* @param listener
|
||||
*/
|
||||
_offUserChanged(listener: Function) {
|
||||
return () => {
|
||||
getLogger(this).info('Removing onUserChanged listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this, 'onUserChanged'), listener);
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this, 'onUserChanged'),
|
||||
listener
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,15 +199,54 @@ export default class Auth extends ModuleBase {
|
|||
* @return {Promise}
|
||||
*/
|
||||
signOut(): Promise<void> {
|
||||
return this._interceptUndefinedUserValue(getNativeModule(this).signOut());
|
||||
return getNativeModule(this)
|
||||
.signOut()
|
||||
.then(() => {
|
||||
this._setUser();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a user in anonymously
|
||||
* @deprecated Deprecated signInAnonymously in favor of signInAnonymouslyAndRetrieveData.
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
signInAnonymously(): Promise<User> {
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.signInAnonymously in favor of firebase.User.prototype.signInAnonymouslyAndRetrieveData.'
|
||||
);
|
||||
return getNativeModule(this)
|
||||
.signInAnonymously()
|
||||
.then(user => this._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a user in anonymously
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
signInAnonymously(): Promise<User> {
|
||||
return this._interceptUserValue(getNativeModule(this).signInAnonymously());
|
||||
signInAnonymouslyAndRetrieveData(): Promise<UserCredential> {
|
||||
return getNativeModule(this)
|
||||
.signInAnonymouslyAndRetrieveData()
|
||||
.then(userCredential => this._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a user with the email/password functionality
|
||||
* @deprecated Deprecated createUserWithEmailAndPassword in favor of createUserAndRetrieveDataWithEmailAndPassword.
|
||||
* @param {string} email The user's email
|
||||
* @param {string} password The user's password
|
||||
* @return {Promise} A promise indicating the completion
|
||||
*/
|
||||
createUserWithEmailAndPassword(
|
||||
email: string,
|
||||
password: string
|
||||
): Promise<User> {
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.createUserWithEmailAndPassword in favor of firebase.User.prototype.createUserAndRetrieveDataWithEmailAndPassword.'
|
||||
);
|
||||
return getNativeModule(this)
|
||||
.createUserWithEmailAndPassword(email, password)
|
||||
.then(user => this._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -218,8 +255,29 @@ export default class Auth extends ModuleBase {
|
|||
* @param {string} password The user's password
|
||||
* @return {Promise} A promise indicating the completion
|
||||
*/
|
||||
createUserWithEmailAndPassword(email: string, password: string): Promise<User> {
|
||||
return this._interceptUserValue(getNativeModule(this).createUserWithEmailAndPassword(email, password));
|
||||
createUserAndRetrieveDataWithEmailAndPassword(
|
||||
email: string,
|
||||
password: string
|
||||
): Promise<User> {
|
||||
return getNativeModule(this)
|
||||
.createUserAndRetrieveDataWithEmailAndPassword(email, password)
|
||||
.then(userCredential => this._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign a user in with email/password
|
||||
* @deprecated Deprecated signInWithEmailAndPassword in favor of signInAndRetrieveDataWithEmailAndPassword
|
||||
* @param {string} email The user's email
|
||||
* @param {string} password The user's password
|
||||
* @return {Promise} A promise that is resolved upon completion
|
||||
*/
|
||||
signInWithEmailAndPassword(email: string, password: string): Promise<User> {
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.signInWithEmailAndPassword in favor of firebase.User.prototype.signInAndRetrieveDataWithEmailAndPassword.'
|
||||
);
|
||||
return getNativeModule(this)
|
||||
.signInWithEmailAndPassword(email, password)
|
||||
.then(user => this._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -228,8 +286,28 @@ export default class Auth extends ModuleBase {
|
|||
* @param {string} password The user's password
|
||||
* @return {Promise} A promise that is resolved upon completion
|
||||
*/
|
||||
signInWithEmailAndPassword(email: string, password: string): Promise<User> {
|
||||
return this._interceptUserValue(getNativeModule(this).signInWithEmailAndPassword(email, password));
|
||||
signInAndRetrieveDataWithEmailAndPassword(
|
||||
email: string,
|
||||
password: string
|
||||
): Promise<UserCredential> {
|
||||
return getNativeModule(this)
|
||||
.signInAndRetrieveDataWithEmailAndPassword(email, password)
|
||||
.then(userCredential => this._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the user in with a custom auth token
|
||||
* @deprecated Deprecated signInWithCustomToken in favor of signInAndRetrieveDataWithCustomToken
|
||||
* @param {string} customToken A self-signed custom auth token.
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
signInWithCustomToken(customToken: string): Promise<User> {
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.signInWithCustomToken in favor of firebase.User.prototype.signInAndRetrieveDataWithCustomToken.'
|
||||
);
|
||||
return getNativeModule(this)
|
||||
.signInWithCustomToken(customToken)
|
||||
.then(user => this._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -237,20 +315,46 @@ export default class Auth extends ModuleBase {
|
|||
* @param {string} customToken A self-signed custom auth token.
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
signInWithCustomToken(customToken: string): Promise<User> {
|
||||
return this._interceptUserValue(getNativeModule(this).signInWithCustomToken(customToken));
|
||||
signInAndRetrieveDataWithCustomToken(
|
||||
customToken: string
|
||||
): Promise<UserCredential> {
|
||||
return getNativeModule(this)
|
||||
.signInAndRetrieveDataWithCustomToken(customToken)
|
||||
.then(userCredential => this._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the user in with a third-party authentication provider
|
||||
* @deprecated Deprecated signInWithCredential in favor of signInAndRetrieveDataWithCredential.
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
signInWithCredential(credential: AuthCredential): Promise<User> {
|
||||
console.warn(
|
||||
'Deprecated firebase.User.prototype.signInWithCredential in favor of firebase.User.prototype.signInAndRetrieveDataWithCredential.'
|
||||
);
|
||||
return getNativeModule(this)
|
||||
.signInWithCredential(
|
||||
credential.providerId,
|
||||
credential.token,
|
||||
credential.secret
|
||||
)
|
||||
.then(user => this._setUser(user));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign the user in with a third-party authentication provider
|
||||
* @return {Promise} A promise resolved upon completion
|
||||
*/
|
||||
signInWithCredential(credential: AuthCredential): Promise<User> {
|
||||
return this._interceptUserValue(
|
||||
getNativeModule(this).signInWithCredential(
|
||||
credential.providerId, credential.token, credential.secret,
|
||||
),
|
||||
);
|
||||
signInAndRetrieveDataWithCredential(
|
||||
credential: AuthCredential
|
||||
): Promise<UserCredential> {
|
||||
return getNativeModule(this)
|
||||
.signInAndRetrieveDataWithCredential(
|
||||
credential.providerId,
|
||||
credential.token,
|
||||
credential.secret
|
||||
)
|
||||
.then(userCredential => this._setUserCredential(userCredential));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -258,9 +362,9 @@ export default class Auth extends ModuleBase {
|
|||
*
|
||||
*/
|
||||
signInWithPhoneNumber(phoneNumber: string): Promise<ConfirmationResult> {
|
||||
return getNativeModule(this).signInWithPhoneNumber(phoneNumber).then((result) => {
|
||||
return new ConfirmationResult(this, result.verificationId);
|
||||
});
|
||||
return getNativeModule(this)
|
||||
.signInWithPhoneNumber(phoneNumber)
|
||||
.then(result => new ConfirmationResult(this, result.verificationId));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -272,7 +376,10 @@ export default class Auth extends ModuleBase {
|
|||
* @param autoVerifyTimeout Android Only
|
||||
* @returns {PhoneAuthListener}
|
||||
*/
|
||||
verifyPhoneNumber(phoneNumber: string, autoVerifyTimeout?: number): PhoneAuthListener {
|
||||
verifyPhoneNumber(
|
||||
phoneNumber: string,
|
||||
autoVerifyTimeout?: number
|
||||
): PhoneAuthListener {
|
||||
return new PhoneAuthListener(this, phoneNumber, autoVerifyTimeout);
|
||||
}
|
||||
|
||||
|
@ -280,8 +387,14 @@ export default class Auth extends ModuleBase {
|
|||
* Send reset password instructions via email
|
||||
* @param {string} email The email to send password reset instructions
|
||||
*/
|
||||
sendPasswordResetEmail(email: string, actionCodeSettings?: ActionCodeSettings): Promise<void> {
|
||||
return getNativeModule(this).sendPasswordResetEmail(email, actionCodeSettings);
|
||||
sendPasswordResetEmail(
|
||||
email: string,
|
||||
actionCodeSettings?: ActionCodeSettings
|
||||
): Promise<void> {
|
||||
return getNativeModule(this).sendPasswordResetEmail(
|
||||
email,
|
||||
actionCodeSettings
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -314,26 +427,32 @@ export default class Auth extends ModuleBase {
|
|||
* @param code
|
||||
* @return {Promise.<any>|Promise<ActionCodeInfo>}
|
||||
*/
|
||||
checkActionCode(code: string): Promise<void> {
|
||||
checkActionCode(code: string): Promise<ActionCodeInfo> {
|
||||
return getNativeModule(this).checkActionCode(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently signed in user
|
||||
* @return {Promise}
|
||||
*/
|
||||
getCurrentUser(): Promise<User | null> {
|
||||
return this._interceptUserValue(getNativeModule(this).getCurrentUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of authentication providers that can be used to sign in a given user (identified by its main email address).
|
||||
* @return {Promise}
|
||||
*/
|
||||
fetchProvidersForEmail(email: string): Promise<Array<String>> {
|
||||
fetchProvidersForEmail(email: string): Promise<string[]> {
|
||||
return getNativeModule(this).fetchProvidersForEmail(email);
|
||||
}
|
||||
|
||||
verifyPasswordResetCode(code: string): Promise<string> {
|
||||
return getNativeModule(this).verifyPasswordResetCode(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the language for the auth module
|
||||
* @param code
|
||||
* @returns {*}
|
||||
*/
|
||||
set languageCode(code: string) {
|
||||
this._languageCode = code;
|
||||
getNativeModule(this).setLanguageCode(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently signed in user
|
||||
* @return {Promise}
|
||||
|
@ -342,28 +461,58 @@ export default class Auth extends ModuleBase {
|
|||
return this._user;
|
||||
}
|
||||
|
||||
get languageCode(): string {
|
||||
return this._languageCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* KNOWN UNSUPPORTED METHODS
|
||||
*/
|
||||
|
||||
getRedirectResult() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'getRedirectResult'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(
|
||||
'auth',
|
||||
'getRedirectResult'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
setPersistence() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'setPersistence'));
|
||||
}
|
||||
|
||||
signInAndRetrieveDataWithCredential() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'signInAndRetrieveDataWithCredential'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(
|
||||
'auth',
|
||||
'setPersistence'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
signInWithPopup() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'signInWithPopup'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(
|
||||
'auth',
|
||||
'signInWithPopup'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
signInWithRedirect() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('auth', 'signInWithRedirect'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(
|
||||
'auth',
|
||||
'signInWithRedirect'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// firebase issue - https://github.com/invertase/react-native-firebase/pull/655#issuecomment-349904680
|
||||
useDeviceLanguage() {
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(
|
||||
'auth',
|
||||
'useDeviceLanguage'
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -374,6 +523,7 @@ export const statics = {
|
|||
GithubAuthProvider,
|
||||
TwitterAuthProvider,
|
||||
FacebookAuthProvider,
|
||||
OAuthProvider,
|
||||
PhoneAuthState: {
|
||||
CODE_SENT: 'sent',
|
||||
AUTO_VERIFY_TIMEOUT: 'timeout',
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
* @flow
|
||||
* EmailAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../../../types';
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'password';
|
||||
|
||||
export default class EmailAuthProvider {
|
||||
constructor() {
|
||||
throw new Error('`new EmailAuthProvider()` is not supported on the native Firebase SDKs.');
|
||||
throw new Error(
|
||||
'`new EmailAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
* @flow
|
||||
* FacebookAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../../../types';
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'facebook.com';
|
||||
|
||||
export default class FacebookAuthProvider {
|
||||
constructor() {
|
||||
throw new Error('`new FacebookAuthProvider()` is not supported on the native Firebase SDKs.');
|
||||
throw new Error(
|
||||
'`new FacebookAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
* @flow
|
||||
* GithubAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../../../types';
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'github.com';
|
||||
|
||||
export default class GithubAuthProvider {
|
||||
constructor() {
|
||||
throw new Error('`new GithubAuthProvider()` is not supported on the native Firebase SDKs.');
|
||||
throw new Error(
|
||||
'`new GithubAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
* @flow
|
||||
* EmailAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../../../types';
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'google.com';
|
||||
|
||||
export default class GoogleAuthProvider {
|
||||
constructor() {
|
||||
throw new Error('`new GoogleAuthProvider()` is not supported on the native Firebase SDKs.');
|
||||
throw new Error(
|
||||
'`new GoogleAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/**
|
||||
* @flow
|
||||
* OAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'oauth';
|
||||
|
||||
export default class OAuthProvider {
|
||||
constructor() {
|
||||
throw new Error(
|
||||
'`new OAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
return providerId;
|
||||
}
|
||||
|
||||
static credential(idToken: string, accessToken: string): AuthCredential {
|
||||
return {
|
||||
token: idToken,
|
||||
secret: accessToken,
|
||||
providerId,
|
||||
};
|
||||
}
|
||||
}
|
|
@ -2,13 +2,15 @@
|
|||
* @flow
|
||||
* PhoneAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../../../types';
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'phone';
|
||||
|
||||
export default class PhoneAuthProvider {
|
||||
constructor() {
|
||||
throw new Error('`new PhoneAuthProvider()` is not supported on the native Firebase SDKs.');
|
||||
throw new Error(
|
||||
'`new PhoneAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
|
|
|
@ -2,13 +2,15 @@
|
|||
* @flow
|
||||
* TwitterAuthProvider representation wrapper
|
||||
*/
|
||||
import type { AuthCredential } from '../../../types';
|
||||
import type { AuthCredential } from '../types';
|
||||
|
||||
const providerId = 'twitter.com';
|
||||
|
||||
export default class TwitterAuthProvider {
|
||||
constructor() {
|
||||
throw new Error('`new TwitterAuthProvider()` is not supported on the native Firebase SDKs.');
|
||||
throw new Error(
|
||||
'`new TwitterAuthProvider()` is not supported on the native Firebase SDKs.'
|
||||
);
|
||||
}
|
||||
|
||||
static get PROVIDER_ID(): string {
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
import type User from './User';
|
||||
|
||||
export type ActionCodeSettings = {
|
||||
android: {
|
||||
installApp?: boolean,
|
||||
minimumVersion?: string,
|
||||
packageName: string,
|
||||
},
|
||||
handleCodeInApp?: boolean,
|
||||
iOS: {
|
||||
bundleId?: string,
|
||||
},
|
||||
url: string,
|
||||
};
|
||||
|
||||
type AdditionalUserInfo = {
|
||||
isNewUser: boolean,
|
||||
profile?: Object,
|
||||
providerId: string,
|
||||
username?: string,
|
||||
};
|
||||
|
||||
export type AuthCredential = {
|
||||
providerId: string,
|
||||
token: string,
|
||||
secret: string,
|
||||
};
|
||||
|
||||
export type UserCredential = {|
|
||||
additionalUserInfo?: AdditionalUserInfo,
|
||||
user: User,
|
||||
|};
|
||||
|
||||
export type UserInfo = {
|
||||
displayName?: string,
|
||||
email?: string,
|
||||
phoneNumber?: string,
|
||||
photoURL?: string,
|
||||
providerId: string,
|
||||
uid: string,
|
||||
};
|
||||
|
||||
export type UserMetadata = {
|
||||
creationTime?: string,
|
||||
lastSignInTime?: string,
|
||||
};
|
||||
|
||||
export type NativeUser = {
|
||||
displayName?: string,
|
||||
email?: string,
|
||||
emailVerified?: boolean,
|
||||
isAnonymous?: boolean,
|
||||
metadata: UserMetadata,
|
||||
phoneNumber?: string,
|
||||
photoURL?: string,
|
||||
providerData: UserInfo[],
|
||||
providerId: string,
|
||||
uid: string,
|
||||
};
|
||||
|
||||
export type NativeUserCredential = {|
|
||||
additionalUserInfo?: AdditionalUserInfo,
|
||||
user: NativeUser,
|
||||
|};
|
|
@ -13,8 +13,11 @@ type NativeValue = {
|
|||
numberValue?: number,
|
||||
dataValue?: Object,
|
||||
boolValue?: boolean,
|
||||
source: 'remoteConfigSourceRemote' | 'remoteConfigSourceDefault' | ' remoteConfigSourceStatic',
|
||||
}
|
||||
source:
|
||||
| 'remoteConfigSourceRemote'
|
||||
| 'remoteConfigSourceDefault'
|
||||
| ' remoteConfigSourceStatic',
|
||||
};
|
||||
|
||||
export const MODULE_NAME = 'RNFirebaseRemoteConfig';
|
||||
export const NAMESPACE = 'config';
|
||||
|
@ -28,6 +31,7 @@ export default class RemoteConfig extends ModuleBase {
|
|||
constructor(app: App) {
|
||||
super(app, {
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
this._developerModeEnabled = false;
|
||||
|
@ -43,9 +47,26 @@ export default class RemoteConfig extends ModuleBase {
|
|||
return {
|
||||
source: nativeValue.source,
|
||||
val() {
|
||||
if (nativeValue.boolValue !== null && (nativeValue.stringValue === 'true' || nativeValue.stringValue === 'false' || nativeValue.stringValue === null)) return nativeValue.boolValue;
|
||||
if (nativeValue.numberValue !== null && nativeValue.numberValue !== undefined && (nativeValue.stringValue == null || nativeValue.stringValue === '' || nativeValue.numberValue.toString() === nativeValue.stringValue)) return nativeValue.numberValue;
|
||||
if (nativeValue.dataValue !== nativeValue.stringValue && (nativeValue.stringValue == null || nativeValue.stringValue === '')) return nativeValue.dataValue;
|
||||
if (
|
||||
nativeValue.boolValue !== null &&
|
||||
(nativeValue.stringValue === 'true' ||
|
||||
nativeValue.stringValue === 'false' ||
|
||||
nativeValue.stringValue === null)
|
||||
)
|
||||
return nativeValue.boolValue;
|
||||
if (
|
||||
nativeValue.numberValue !== null &&
|
||||
nativeValue.numberValue !== undefined &&
|
||||
(nativeValue.stringValue == null ||
|
||||
nativeValue.stringValue === '' ||
|
||||
nativeValue.numberValue.toString() === nativeValue.stringValue)
|
||||
)
|
||||
return nativeValue.numberValue;
|
||||
if (
|
||||
nativeValue.dataValue !== nativeValue.stringValue &&
|
||||
(nativeValue.stringValue == null || nativeValue.stringValue === '')
|
||||
)
|
||||
return nativeValue.dataValue;
|
||||
return nativeValue.stringValue;
|
||||
},
|
||||
};
|
||||
|
@ -69,7 +90,9 @@ export default class RemoteConfig extends ModuleBase {
|
|||
*/
|
||||
fetch(expiration?: number) {
|
||||
if (expiration !== undefined) {
|
||||
getLogger(this).debug(`Fetching remote config data with expiration ${expiration.toString()}`);
|
||||
getLogger(this).debug(
|
||||
`Fetching remote config data with expiration ${expiration.toString()}`
|
||||
);
|
||||
return getNativeModule(this).fetchWithExpirationDuration(expiration);
|
||||
}
|
||||
getLogger(this).debug('Fetching remote config data');
|
||||
|
@ -123,7 +146,7 @@ export default class RemoteConfig extends ModuleBase {
|
|||
getValues(keys: Array<String>) {
|
||||
return getNativeModule(this)
|
||||
.getValues(keys || [])
|
||||
.then((nativeValues) => {
|
||||
.then(nativeValues => {
|
||||
const values: { [String]: Object } = {};
|
||||
for (let i = 0, len = keys.length; i < len; i++) {
|
||||
values[keys[i]] = this._nativeValueToJS(nativeValues[i]);
|
||||
|
|
|
@ -13,7 +13,9 @@ import Auth, { NAMESPACE as AuthNamespace } from '../auth';
|
|||
import Analytics, { NAMESPACE as AnalyticsNamespace } from '../analytics';
|
||||
import Config, { NAMESPACE as ConfigNamespace } from '../config';
|
||||
import Crash, { NAMESPACE as CrashNamespace } from '../crash';
|
||||
import Crashlytics, { NAMESPACE as CrashlyticsNamespace } from '../fabric/crashlytics';
|
||||
import Crashlytics, {
|
||||
NAMESPACE as CrashlyticsNamespace,
|
||||
} from '../fabric/crashlytics';
|
||||
import Database, { NAMESPACE as DatabaseNamespace } from '../database';
|
||||
import Firestore, { NAMESPACE as FirestoreNamespace } from '../firestore';
|
||||
import Links, { NAMESPACE as LinksNamespace } from '../links';
|
||||
|
@ -22,15 +24,12 @@ import Performance, { NAMESPACE as PerfNamespace } from '../perf';
|
|||
import Storage, { NAMESPACE as StorageNamespace } from '../storage';
|
||||
import Utils, { NAMESPACE as UtilsNamespace } from '../utils';
|
||||
|
||||
import type {
|
||||
FirebaseOptions,
|
||||
} from '../../types';
|
||||
import type { FirebaseOptions } from '../../types';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
|
||||
export default class App {
|
||||
_extendedProps: { [string] : boolean };
|
||||
_extendedProps: { [string]: boolean };
|
||||
_initialized: boolean = false;
|
||||
_name: string;
|
||||
_nativeInitialized: boolean = false;
|
||||
|
@ -51,7 +50,11 @@ export default class App {
|
|||
storage: () => Storage;
|
||||
utils: () => Utils;
|
||||
|
||||
constructor(name: string, options: FirebaseOptions, fromNative: boolean = false) {
|
||||
constructor(
|
||||
name: string,
|
||||
options: FirebaseOptions,
|
||||
fromNative: boolean = false
|
||||
) {
|
||||
this._name = name;
|
||||
this._options = Object.assign({}, options);
|
||||
|
||||
|
@ -59,10 +62,14 @@ export default class App {
|
|||
this._initialized = true;
|
||||
this._nativeInitialized = true;
|
||||
} else if (options.databaseURL && options.apiKey) {
|
||||
FirebaseCoreModule.initializeApp(this._name, this._options, (error, result) => {
|
||||
FirebaseCoreModule.initializeApp(
|
||||
this._name,
|
||||
this._options,
|
||||
(error, result) => {
|
||||
this._initialized = true;
|
||||
SharedEventEmitter.emit(`AppReady:${this._name}`, { error, result });
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// modules
|
||||
|
@ -109,7 +116,10 @@ export default class App {
|
|||
* @param props
|
||||
*/
|
||||
extendApp(props: Object) {
|
||||
if (!isObject(props)) throw new Error(INTERNALS.STRINGS.ERROR_MISSING_ARG('Object', 'extendApp'));
|
||||
if (!isObject(props))
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_MISSING_ARG('Object', 'extendApp')
|
||||
);
|
||||
const keys = Object.keys(props);
|
||||
|
||||
for (let i = 0, len = keys.length; i < len; i++) {
|
||||
|
@ -130,7 +140,9 @@ export default class App {
|
|||
* @return {Promise}
|
||||
*/
|
||||
delete() {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_CLASS_METHOD('app', 'delete')
|
||||
);
|
||||
// TODO only the ios sdk currently supports delete, add back in when android also supports it
|
||||
// if (this._name === APPS.DEFAULT_APP_NAME && this._nativeInitialized) {
|
||||
// return Promise.reject(
|
||||
|
@ -141,7 +153,6 @@ export default class App {
|
|||
// return FirebaseCoreModule.deleteApp(this._name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {*}
|
||||
|
|
|
@ -7,21 +7,58 @@ import { NativeModules } from 'react-native';
|
|||
import APPS from '../../utils/apps';
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import App from './firebase-app';
|
||||
import VERSION from '../../version';
|
||||
|
||||
// module imports
|
||||
import { statics as AdMobStatics, MODULE_NAME as AdmobModuleName } from '../admob';
|
||||
import {
|
||||
statics as AdMobStatics,
|
||||
MODULE_NAME as AdmobModuleName,
|
||||
} from '../admob';
|
||||
import { statics as AuthStatics, MODULE_NAME as AuthModuleName } from '../auth';
|
||||
import { statics as AnalyticsStatics, MODULE_NAME as AnalyticsModuleName } from '../analytics';
|
||||
import { statics as ConfigStatics, MODULE_NAME as ConfigModuleName } from '../config';
|
||||
import { statics as CrashStatics, MODULE_NAME as CrashModuleName } from '../crash';
|
||||
import { statics as CrashlyticsStatics, MODULE_NAME as CrashlyticsModuleName } from '../fabric/crashlytics';
|
||||
import { statics as DatabaseStatics, MODULE_NAME as DatabaseModuleName } from '../database';
|
||||
import { statics as FirestoreStatics, MODULE_NAME as FirestoreModuleName } from '../firestore';
|
||||
import { statics as LinksStatics, MODULE_NAME as LinksModuleName } from '../links';
|
||||
import { statics as MessagingStatics, MODULE_NAME as MessagingModuleName } from '../messaging';
|
||||
import { statics as PerformanceStatics, MODULE_NAME as PerfModuleName } from '../perf';
|
||||
import { statics as StorageStatics, MODULE_NAME as StorageModuleName } from '../storage';
|
||||
import { statics as UtilsStatics, MODULE_NAME as UtilsModuleName } from '../utils';
|
||||
import {
|
||||
statics as AnalyticsStatics,
|
||||
MODULE_NAME as AnalyticsModuleName,
|
||||
} from '../analytics';
|
||||
import {
|
||||
statics as ConfigStatics,
|
||||
MODULE_NAME as ConfigModuleName,
|
||||
} from '../config';
|
||||
import {
|
||||
statics as CrashStatics,
|
||||
MODULE_NAME as CrashModuleName,
|
||||
} from '../crash';
|
||||
import {
|
||||
statics as CrashlyticsStatics,
|
||||
MODULE_NAME as CrashlyticsModuleName,
|
||||
} from '../fabric/crashlytics';
|
||||
import {
|
||||
statics as DatabaseStatics,
|
||||
MODULE_NAME as DatabaseModuleName,
|
||||
} from '../database';
|
||||
import {
|
||||
statics as FirestoreStatics,
|
||||
MODULE_NAME as FirestoreModuleName,
|
||||
} from '../firestore';
|
||||
import {
|
||||
statics as LinksStatics,
|
||||
MODULE_NAME as LinksModuleName,
|
||||
} from '../links';
|
||||
import {
|
||||
statics as MessagingStatics,
|
||||
MODULE_NAME as MessagingModuleName,
|
||||
} from '../messaging';
|
||||
import {
|
||||
statics as PerformanceStatics,
|
||||
MODULE_NAME as PerfModuleName,
|
||||
} from '../perf';
|
||||
import {
|
||||
statics as StorageStatics,
|
||||
MODULE_NAME as StorageModuleName,
|
||||
} from '../storage';
|
||||
import {
|
||||
statics as UtilsStatics,
|
||||
MODULE_NAME as UtilsModuleName,
|
||||
} from '../utils';
|
||||
|
||||
import type {
|
||||
AdMobModule,
|
||||
|
@ -59,25 +96,57 @@ class Firebase {
|
|||
|
||||
constructor() {
|
||||
if (!FirebaseCoreModule) {
|
||||
throw (new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE));
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_CORE);
|
||||
}
|
||||
APPS.initializeNativeApps();
|
||||
|
||||
// modules
|
||||
this.admob = APPS.moduleAndStatics('admob', AdMobStatics, AdmobModuleName);
|
||||
this.analytics = APPS.moduleAndStatics('analytics', AnalyticsStatics, AnalyticsModuleName);
|
||||
this.analytics = APPS.moduleAndStatics(
|
||||
'analytics',
|
||||
AnalyticsStatics,
|
||||
AnalyticsModuleName
|
||||
);
|
||||
this.auth = APPS.moduleAndStatics('auth', AuthStatics, AuthModuleName);
|
||||
this.config = APPS.moduleAndStatics('config', ConfigStatics, ConfigModuleName);
|
||||
this.config = APPS.moduleAndStatics(
|
||||
'config',
|
||||
ConfigStatics,
|
||||
ConfigModuleName
|
||||
);
|
||||
this.crash = APPS.moduleAndStatics('crash', CrashStatics, CrashModuleName);
|
||||
this.database = APPS.moduleAndStatics('database', DatabaseStatics, DatabaseModuleName);
|
||||
this.database = APPS.moduleAndStatics(
|
||||
'database',
|
||||
DatabaseStatics,
|
||||
DatabaseModuleName
|
||||
);
|
||||
this.fabric = {
|
||||
crashlytics: APPS.moduleAndStatics('crashlytics', CrashlyticsStatics, CrashlyticsModuleName),
|
||||
crashlytics: APPS.moduleAndStatics(
|
||||
'crashlytics',
|
||||
CrashlyticsStatics,
|
||||
CrashlyticsModuleName
|
||||
),
|
||||
};
|
||||
this.firestore = APPS.moduleAndStatics('firestore', FirestoreStatics, FirestoreModuleName);
|
||||
this.firestore = APPS.moduleAndStatics(
|
||||
'firestore',
|
||||
FirestoreStatics,
|
||||
FirestoreModuleName
|
||||
);
|
||||
this.links = APPS.moduleAndStatics('links', LinksStatics, LinksModuleName);
|
||||
this.messaging = APPS.moduleAndStatics('messaging', MessagingStatics, MessagingModuleName);
|
||||
this.perf = APPS.moduleAndStatics('perf', PerformanceStatics, PerfModuleName);
|
||||
this.storage = APPS.moduleAndStatics('storage', StorageStatics, StorageModuleName);
|
||||
this.messaging = APPS.moduleAndStatics(
|
||||
'messaging',
|
||||
MessagingStatics,
|
||||
MessagingModuleName
|
||||
);
|
||||
this.perf = APPS.moduleAndStatics(
|
||||
'perf',
|
||||
PerformanceStatics,
|
||||
PerfModuleName
|
||||
);
|
||||
this.storage = APPS.moduleAndStatics(
|
||||
'storage',
|
||||
StorageStatics,
|
||||
StorageModuleName
|
||||
);
|
||||
this.utils = APPS.moduleAndStatics('utils', UtilsStatics, UtilsModuleName);
|
||||
}
|
||||
|
||||
|
@ -112,6 +181,14 @@ class Firebase {
|
|||
get apps(): Array<App> {
|
||||
return APPS.apps();
|
||||
}
|
||||
|
||||
/**
|
||||
* The current SDK version.
|
||||
* @return {string}
|
||||
*/
|
||||
get SDK_VERSION(): string {
|
||||
return VERSION;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Firebase();
|
||||
|
|
|
@ -15,6 +15,7 @@ export default class Crash extends ModuleBase {
|
|||
constructor(app: App) {
|
||||
super(app, {
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ import { getNativeModule } from '../../utils/native';
|
|||
import type Database from './';
|
||||
import type Reference from './reference';
|
||||
|
||||
|
||||
/**
|
||||
* @url https://firebase.google.com/docs/reference/js/firebase.database.OnDisconnect
|
||||
* @class Disconnect
|
||||
|
@ -33,7 +32,10 @@ export default class Disconnect {
|
|||
* @returns {*}
|
||||
*/
|
||||
set(value: string | Object): Promise<void> {
|
||||
return getNativeModule(this._database).onDisconnectSet(this.path, { type: typeOf(value), value });
|
||||
return getNativeModule(this._database).onDisconnectSet(this.path, {
|
||||
type: typeOf(value),
|
||||
value,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,7 +44,10 @@ export default class Disconnect {
|
|||
* @returns {*}
|
||||
*/
|
||||
update(values: Object): Promise<void> {
|
||||
return getNativeModule(this._database).onDisconnectUpdate(this.path, values);
|
||||
return getNativeModule(this._database).onDisconnectUpdate(
|
||||
this.path,
|
||||
values
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,7 @@ export default class Database extends ModuleBase {
|
|||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: true,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
this._transactionHandler = new TransactionHandler(this);
|
||||
|
@ -46,7 +47,7 @@ export default class Database extends ModuleBase {
|
|||
setTimeout(() => {
|
||||
this._serverTimeOffset = 0;
|
||||
this._offsetRef = this.ref('.info/serverTimeOffset');
|
||||
this._offsetRef.on('value', (snapshot) => {
|
||||
this._offsetRef.on('value', snapshot => {
|
||||
this._serverTimeOffset = snapshot.val() || this._serverTimeOffset;
|
||||
});
|
||||
}, 1);
|
||||
|
@ -85,9 +86,13 @@ export default class Database extends ModuleBase {
|
|||
}
|
||||
|
||||
export const statics = {
|
||||
ServerValue: NativeModules.RNFirebaseDatabase ? {
|
||||
TIMESTAMP: NativeModules.RNFirebaseDatabase.serverValueTimestamp || { '.sv': 'timestamp' },
|
||||
} : {},
|
||||
ServerValue: NativeModules.RNFirebaseDatabase
|
||||
? {
|
||||
TIMESTAMP: NativeModules.RNFirebaseDatabase.serverValueTimestamp || {
|
||||
'.sv': 'timestamp',
|
||||
},
|
||||
}
|
||||
: {},
|
||||
enableLogging(enabled: boolean) {
|
||||
if (NativeModules[MODULE_NAME]) {
|
||||
NativeModules[MODULE_NAME].enableLogging(enabled);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
import { objectToUniqueId } from '../../utils';
|
||||
|
||||
import type { DatabaseModifier } from '../../types';
|
||||
import type Reference from './reference.js';
|
||||
import type Reference from './reference';
|
||||
|
||||
// todo doc methods
|
||||
|
||||
|
@ -16,7 +16,7 @@ export default class Query {
|
|||
_reference: Reference;
|
||||
modifiers: Array<DatabaseModifier>;
|
||||
|
||||
constructor(ref: Reference, path: string, existingModifiers?: Array<DatabaseModifier>) {
|
||||
constructor(ref: Reference, existingModifiers?: Array<DatabaseModifier>) {
|
||||
this.modifiers = existingModifiers ? [...existingModifiers] : [];
|
||||
this._reference = ref;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* @flow
|
||||
* Database Reference representation wrapper
|
||||
*/
|
||||
import Query from './query.js';
|
||||
import Query from './query';
|
||||
import Snapshot from './snapshot';
|
||||
import Disconnect from './disconnect';
|
||||
import { getLogger } from '../../utils/log';
|
||||
|
@ -41,11 +41,11 @@ const ReferenceEventTypes = {
|
|||
};
|
||||
|
||||
type DatabaseListener = {
|
||||
listenerId: number;
|
||||
eventName: string;
|
||||
successCallback: Function;
|
||||
failureCallback?: Function;
|
||||
}
|
||||
listenerId: number,
|
||||
eventName: string,
|
||||
successCallback: Function,
|
||||
failureCallback?: Function,
|
||||
};
|
||||
|
||||
/**
|
||||
* @typedef {String} ReferenceLocation - Path to location in the database, relative
|
||||
|
@ -80,12 +80,16 @@ export default class Reference extends ReferenceBase {
|
|||
_query: Query;
|
||||
_refListeners: { [listenerId: number]: DatabaseListener };
|
||||
|
||||
constructor(database: Database, path: string, existingModifiers?: Array<DatabaseModifier>) {
|
||||
constructor(
|
||||
database: Database,
|
||||
path: string,
|
||||
existingModifiers?: Array<DatabaseModifier>
|
||||
) {
|
||||
super(path);
|
||||
this._promise = null;
|
||||
this._refListeners = {};
|
||||
this._database = database;
|
||||
this._query = new Query(this, path, existingModifiers);
|
||||
this._query = new Query(this, existingModifiers);
|
||||
getLogger(database).debug('Created new Reference', this._getRefKey());
|
||||
}
|
||||
|
||||
|
@ -100,7 +104,12 @@ export default class Reference extends ReferenceBase {
|
|||
* @returns {*}
|
||||
*/
|
||||
keepSynced(bool: boolean): Promise<void> {
|
||||
return getNativeModule(this._database).keepSynced(this._getRefKey(), this.path, this._query.getModifiers(), bool);
|
||||
return getNativeModule(this._database).keepSynced(
|
||||
this._getRefKey(),
|
||||
this.path,
|
||||
this._query.getModifiers(),
|
||||
bool
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -113,8 +122,11 @@ export default class Reference extends ReferenceBase {
|
|||
*/
|
||||
set(value: any, onComplete?: Function): Promise<void> {
|
||||
return promiseOrCallback(
|
||||
getNativeModule(this._database).set(this.path, this._serializeAnyType(value)),
|
||||
onComplete,
|
||||
getNativeModule(this._database).set(
|
||||
this.path,
|
||||
this._serializeAnyType(value)
|
||||
),
|
||||
onComplete
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -126,12 +138,15 @@ export default class Reference extends ReferenceBase {
|
|||
* @param onComplete
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setPriority(priority: string | number | null, onComplete?: Function): Promise<void> {
|
||||
setPriority(
|
||||
priority: string | number | null,
|
||||
onComplete?: Function
|
||||
): Promise<void> {
|
||||
const _priority = this._serializeAnyType(priority);
|
||||
|
||||
return promiseOrCallback(
|
||||
getNativeModule(this._database).setPriority(this.path, _priority),
|
||||
onComplete,
|
||||
onComplete
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -144,13 +159,21 @@ export default class Reference extends ReferenceBase {
|
|||
* @param onComplete
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setWithPriority(value: any, priority: string | number | null, onComplete?: Function): Promise<void> {
|
||||
setWithPriority(
|
||||
value: any,
|
||||
priority: string | number | null,
|
||||
onComplete?: Function
|
||||
): Promise<void> {
|
||||
const _value = this._serializeAnyType(value);
|
||||
const _priority = this._serializeAnyType(priority);
|
||||
|
||||
return promiseOrCallback(
|
||||
getNativeModule(this._database).setWithPriority(this.path, _value, _priority),
|
||||
onComplete,
|
||||
getNativeModule(this._database).setWithPriority(
|
||||
this.path,
|
||||
_value,
|
||||
_priority
|
||||
),
|
||||
onComplete
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -167,7 +190,7 @@ export default class Reference extends ReferenceBase {
|
|||
|
||||
return promiseOrCallback(
|
||||
getNativeModule(this._database).update(this.path, value),
|
||||
onComplete,
|
||||
onComplete
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -181,7 +204,7 @@ export default class Reference extends ReferenceBase {
|
|||
remove(onComplete?: Function): Promise<void> {
|
||||
return promiseOrCallback(
|
||||
getNativeModule(this._database).remove(this.path),
|
||||
onComplete,
|
||||
onComplete
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -196,10 +219,12 @@ export default class Reference extends ReferenceBase {
|
|||
transaction(
|
||||
transactionUpdate: Function,
|
||||
onComplete: (error: ?Error, committed: boolean, snapshot: ?Snapshot) => *,
|
||||
applyLocally: boolean = false,
|
||||
applyLocally: boolean = false
|
||||
) {
|
||||
if (!isFunction(transactionUpdate)) {
|
||||
return Promise.reject(new Error('Missing transactionUpdate function argument.'));
|
||||
return Promise.reject(
|
||||
new Error('Missing transactionUpdate function argument.')
|
||||
);
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -213,15 +238,22 @@ export default class Reference extends ReferenceBase {
|
|||
}
|
||||
|
||||
if (error) return reject(error);
|
||||
return resolve({ committed, snapshot: new Snapshot(this, snapshotData) });
|
||||
return resolve({
|
||||
committed,
|
||||
snapshot: new Snapshot(this, snapshotData),
|
||||
});
|
||||
};
|
||||
|
||||
// start the transaction natively
|
||||
this._database._transactionHandler.add(this, transactionUpdate, onCompleteWrapper, applyLocally);
|
||||
this._database._transactionHandler.add(
|
||||
this,
|
||||
transactionUpdate,
|
||||
onCompleteWrapper,
|
||||
applyLocally
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param eventName
|
||||
|
@ -234,21 +266,24 @@ export default class Reference extends ReferenceBase {
|
|||
eventName: string = 'value',
|
||||
successCallback: (snapshot: Object) => void,
|
||||
cancelOrContext: (error: FirebaseError) => void,
|
||||
context?: Object,
|
||||
context?: Object
|
||||
) {
|
||||
return getNativeModule(this._database).once(this._getRefKey(), this.path, this._query.getModifiers(), eventName)
|
||||
return getNativeModule(this._database)
|
||||
.once(this._getRefKey(), this.path, this._query.getModifiers(), eventName)
|
||||
.then(({ snapshot }) => {
|
||||
const _snapshot = new Snapshot(this, snapshot);
|
||||
|
||||
if (isFunction(successCallback)) {
|
||||
if (isObject(cancelOrContext)) successCallback.bind(cancelOrContext)(_snapshot);
|
||||
if (context && isObject(context)) successCallback.bind(context)(_snapshot);
|
||||
if (isObject(cancelOrContext))
|
||||
successCallback.bind(cancelOrContext)(_snapshot);
|
||||
if (context && isObject(context))
|
||||
successCallback.bind(context)(_snapshot);
|
||||
successCallback(_snapshot);
|
||||
}
|
||||
|
||||
return _snapshot;
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
if (isFunction(cancelOrContext)) return cancelOrContext(error);
|
||||
return error;
|
||||
});
|
||||
|
@ -262,19 +297,27 @@ export default class Reference extends ReferenceBase {
|
|||
*/
|
||||
push(value: any, onComplete?: Function): Reference | Promise<void> {
|
||||
if (value === null || value === undefined) {
|
||||
return new Reference(this._database, `${this.path}/${generatePushID(this._database._serverTimeOffset)}`);
|
||||
return new Reference(
|
||||
this._database,
|
||||
`${this.path}/${generatePushID(this._database._serverTimeOffset)}`
|
||||
);
|
||||
}
|
||||
|
||||
const newRef = new Reference(this._database, `${this.path}/${generatePushID(this._database._serverTimeOffset)}`);
|
||||
const newRef = new Reference(
|
||||
this._database,
|
||||
`${this.path}/${generatePushID(this._database._serverTimeOffset)}`
|
||||
);
|
||||
const promise = newRef.set(value);
|
||||
|
||||
// if callback provided then internally call the set promise with value
|
||||
if (isFunction(onComplete)) {
|
||||
return promise
|
||||
return (
|
||||
promise
|
||||
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
|
||||
.then(() => onComplete(null, newRef))
|
||||
// $FlowBug: Reports that onComplete can change to null despite the null check: https://github.com/facebook/flow/issues/1655
|
||||
.catch(error => onComplete(error, null));
|
||||
.catch(error => onComplete(error, null))
|
||||
);
|
||||
}
|
||||
|
||||
// otherwise attach promise to 'thenable' reference and return the
|
||||
|
@ -327,7 +370,11 @@ export default class Reference extends ReferenceBase {
|
|||
* @returns {Reference}
|
||||
*/
|
||||
orderBy(name: string, key?: string): Reference {
|
||||
const newRef = new Reference(this._database, this.path, this._query.getModifiers());
|
||||
const newRef = new Reference(
|
||||
this._database,
|
||||
this.path,
|
||||
this._query.getModifiers()
|
||||
);
|
||||
newRef._query.orderBy(name, key);
|
||||
return newRef;
|
||||
}
|
||||
|
@ -361,7 +408,11 @@ export default class Reference extends ReferenceBase {
|
|||
* @returns {Reference}
|
||||
*/
|
||||
limit(name: string, limit: number): Reference {
|
||||
const newRef = new Reference(this._database, this.path, this._query.getModifiers());
|
||||
const newRef = new Reference(
|
||||
this._database,
|
||||
this.path,
|
||||
this._query.getModifiers()
|
||||
);
|
||||
newRef._query.limit(name, limit);
|
||||
return newRef;
|
||||
}
|
||||
|
@ -408,7 +459,11 @@ export default class Reference extends ReferenceBase {
|
|||
* @returns {Reference}
|
||||
*/
|
||||
filter(name: string, value: any, key?: string): Reference {
|
||||
const newRef = new Reference(this._database, this.path, this._query.getModifiers());
|
||||
const newRef = new Reference(
|
||||
this._database,
|
||||
this.path,
|
||||
this._query.getModifiers()
|
||||
);
|
||||
newRef._query.filter(name, value, key);
|
||||
return newRef;
|
||||
}
|
||||
|
@ -438,7 +493,7 @@ export default class Reference extends ReferenceBase {
|
|||
* @returns {string}
|
||||
*/
|
||||
toString(): string {
|
||||
return this.path;
|
||||
return `${this._database.app.options.databaseURL}/${this.path}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -450,10 +505,12 @@ export default class Reference extends ReferenceBase {
|
|||
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#isEqual}
|
||||
*/
|
||||
isEqual(otherRef: Reference): boolean {
|
||||
return !!otherRef
|
||||
&& otherRef.constructor === Reference
|
||||
&& otherRef.key === this.key
|
||||
&& this._query.queryIdentifier() === otherRef._query.queryIdentifier();
|
||||
return (
|
||||
!!otherRef &&
|
||||
otherRef.constructor === Reference &&
|
||||
otherRef.key === this.key &&
|
||||
this._query.queryIdentifier() === otherRef._query.queryIdentifier()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,7 +525,10 @@ export default class Reference extends ReferenceBase {
|
|||
*/
|
||||
get parent(): Reference | null {
|
||||
if (this.path === '/') return null;
|
||||
return new Reference(this._database, this.path.substring(0, this.path.lastIndexOf('/')));
|
||||
return new Reference(
|
||||
this._database,
|
||||
this.path.substring(0, this.path.lastIndexOf('/'))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -495,12 +555,14 @@ export default class Reference extends ReferenceBase {
|
|||
* Access then method of promise if set
|
||||
* @return {*}
|
||||
*/
|
||||
then(fnResolve: (any) => any, fnReject: (any) => any) {
|
||||
then(fnResolve: any => any, fnReject: any => any) {
|
||||
if (isFunction(fnResolve) && this._promise && this._promise.then) {
|
||||
return this._promise.then.bind(this._promise)((result) => {
|
||||
return this._promise.then.bind(this._promise)(
|
||||
result => {
|
||||
this._promise = null;
|
||||
return fnResolve(result);
|
||||
}, (possibleErr) => {
|
||||
},
|
||||
possibleErr => {
|
||||
this._promise = null;
|
||||
|
||||
if (isFunction(fnReject)) {
|
||||
|
@ -508,7 +570,8 @@ export default class Reference extends ReferenceBase {
|
|||
}
|
||||
|
||||
throw possibleErr;
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
throw new Error("Cannot read property 'then' of undefined.");
|
||||
|
@ -518,9 +581,9 @@ export default class Reference extends ReferenceBase {
|
|||
* Access catch method of promise if set
|
||||
* @return {*}
|
||||
*/
|
||||
catch(fnReject: (any) => any) {
|
||||
catch(fnReject: any => any) {
|
||||
if (isFunction(fnReject) && this._promise && this._promise.catch) {
|
||||
return this._promise.catch.bind(this._promise)((possibleErr) => {
|
||||
return this._promise.catch.bind(this._promise)(possibleErr => {
|
||||
this._promise = null;
|
||||
return fnReject(possibleErr);
|
||||
});
|
||||
|
@ -539,7 +602,9 @@ export default class Reference extends ReferenceBase {
|
|||
* @return {string}
|
||||
*/
|
||||
_getRegistrationKey(eventType: string): string {
|
||||
return `$${this._database.app.name}$/${this.path}$${this._query.queryIdentifier()}$${listeners}$${eventType}`;
|
||||
return `$${this._database.app.name}$/${
|
||||
this.path
|
||||
}$${this._query.queryIdentifier()}$${listeners}$${eventType}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -550,7 +615,9 @@ export default class Reference extends ReferenceBase {
|
|||
* @private
|
||||
*/
|
||||
_getRefKey(): string {
|
||||
return `$${this._database.app.name}$/${this.path}$${this._query.queryIdentifier()}`;
|
||||
return `$${this._database.app.name}$/${
|
||||
this.path
|
||||
}$${this._query.queryIdentifier()}`;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -562,7 +629,6 @@ export default class Reference extends ReferenceBase {
|
|||
this._promise = promise;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param obj
|
||||
|
@ -623,34 +689,65 @@ export default class Reference extends ReferenceBase {
|
|||
*
|
||||
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#on}
|
||||
*/
|
||||
on(eventType: string, callback: (Snapshot) => any, cancelCallbackOrContext?: (Object) => any | Object, context?: Object): Function {
|
||||
on(
|
||||
eventType: string,
|
||||
callback: Snapshot => any,
|
||||
cancelCallbackOrContext?: Object => any | Object,
|
||||
context?: Object
|
||||
): Function {
|
||||
if (!eventType) {
|
||||
throw new Error('Query.on failed: Function called with 0 arguments. Expects at least 2.');
|
||||
throw new Error(
|
||||
'Query.on failed: Function called with 0 arguments. Expects at least 2.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!isString(eventType) || !ReferenceEventTypes[eventType]) {
|
||||
throw new Error(`Query.on failed: First argument must be a valid string event type: "${Object.keys(ReferenceEventTypes).join(', ')}"`);
|
||||
throw new Error(
|
||||
`Query.on failed: First argument must be a valid string event type: "${Object.keys(
|
||||
ReferenceEventTypes
|
||||
).join(', ')}"`
|
||||
);
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
throw new Error('Query.on failed: Function called with 1 argument. Expects at least 2.');
|
||||
throw new Error(
|
||||
'Query.on failed: Function called with 1 argument. Expects at least 2.'
|
||||
);
|
||||
}
|
||||
|
||||
if (!isFunction(callback)) {
|
||||
throw new Error('Query.on failed: Second argument must be a valid function.');
|
||||
throw new Error(
|
||||
'Query.on failed: Second argument must be a valid function.'
|
||||
);
|
||||
}
|
||||
|
||||
if (cancelCallbackOrContext && !isFunction(cancelCallbackOrContext) && !isObject(context) && !isObject(cancelCallbackOrContext)) {
|
||||
throw new Error('Query.on failed: Function called with 3 arguments, but third optional argument `cancelCallbackOrContext` was not a function.');
|
||||
if (
|
||||
cancelCallbackOrContext &&
|
||||
!isFunction(cancelCallbackOrContext) &&
|
||||
!isObject(context) &&
|
||||
!isObject(cancelCallbackOrContext)
|
||||
) {
|
||||
throw new Error(
|
||||
'Query.on failed: Function called with 3 arguments, but third optional argument `cancelCallbackOrContext` was not a function.'
|
||||
);
|
||||
}
|
||||
|
||||
if (cancelCallbackOrContext && !isFunction(cancelCallbackOrContext) && context) {
|
||||
throw new Error('Query.on failed: Function called with 4 arguments, but third optional argument `cancelCallbackOrContext` was not a function.');
|
||||
if (
|
||||
cancelCallbackOrContext &&
|
||||
!isFunction(cancelCallbackOrContext) &&
|
||||
context
|
||||
) {
|
||||
throw new Error(
|
||||
'Query.on failed: Function called with 4 arguments, but third optional argument `cancelCallbackOrContext` was not a function.'
|
||||
);
|
||||
}
|
||||
|
||||
const eventRegistrationKey = this._getRegistrationKey(eventType);
|
||||
const registrationCancellationKey = `${eventRegistrationKey}$cancelled`;
|
||||
const _context = (cancelCallbackOrContext && !isFunction(cancelCallbackOrContext)) ? cancelCallbackOrContext : context;
|
||||
const _context =
|
||||
cancelCallbackOrContext && !isFunction(cancelCallbackOrContext)
|
||||
? cancelCallbackOrContext
|
||||
: context;
|
||||
const registrationObj = {
|
||||
eventType,
|
||||
ref: this,
|
||||
|
@ -677,7 +774,9 @@ export default class Reference extends ReferenceBase {
|
|||
appName: this._database.app.name,
|
||||
eventType: `${eventType}$cancelled`,
|
||||
eventRegistrationKey: registrationCancellationKey,
|
||||
listener: _context ? cancelCallbackOrContext.bind(_context) : cancelCallbackOrContext,
|
||||
listener: _context
|
||||
? cancelCallbackOrContext.bind(_context)
|
||||
: cancelCallbackOrContext,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -724,18 +823,29 @@ export default class Reference extends ReferenceBase {
|
|||
if (!arguments.length) {
|
||||
// Firebase Docs:
|
||||
// if no eventType or callback is specified, all callbacks for the Reference will be removed.
|
||||
return SyncTree.removeListenersForRegistrations(SyncTree.getRegistrationsByPath(this.path));
|
||||
return SyncTree.removeListenersForRegistrations(
|
||||
SyncTree.getRegistrationsByPath(this.path)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* VALIDATE ARGS
|
||||
*/
|
||||
if (eventType && (!isString(eventType) || !ReferenceEventTypes[eventType])) {
|
||||
throw new Error(`Query.off failed: First argument must be a valid string event type: "${Object.keys(ReferenceEventTypes).join(', ')}"`);
|
||||
if (
|
||||
eventType &&
|
||||
(!isString(eventType) || !ReferenceEventTypes[eventType])
|
||||
) {
|
||||
throw new Error(
|
||||
`Query.off failed: First argument must be a valid string event type: "${Object.keys(
|
||||
ReferenceEventTypes
|
||||
).join(', ')}"`
|
||||
);
|
||||
}
|
||||
|
||||
if (originalCallback && !isFunction(originalCallback)) {
|
||||
throw new Error('Query.off failed: Function called with 2 arguments, but second optional argument was not a function.');
|
||||
throw new Error(
|
||||
'Query.off failed: Function called with 2 arguments, but second optional argument was not a function.'
|
||||
);
|
||||
}
|
||||
|
||||
// Firebase Docs:
|
||||
|
@ -745,7 +855,11 @@ export default class Reference extends ReferenceBase {
|
|||
// remove the callback.
|
||||
// Remove only a single registration
|
||||
if (eventType && originalCallback) {
|
||||
const registration = SyncTree.getOneByPathEventListener(this.path, eventType, originalCallback);
|
||||
const registration = SyncTree.getOneByPathEventListener(
|
||||
this.path,
|
||||
eventType,
|
||||
originalCallback
|
||||
);
|
||||
if (!registration) return [];
|
||||
|
||||
// remove the paired cancellation registration if any exist
|
||||
|
@ -753,15 +867,20 @@ export default class Reference extends ReferenceBase {
|
|||
|
||||
// remove only the first registration to match firebase web sdk
|
||||
// call multiple times to remove multiple registrations
|
||||
return SyncTree.removeListenerRegistrations(originalCallback, [registration]);
|
||||
return SyncTree.removeListenerRegistrations(originalCallback, [
|
||||
registration,
|
||||
]);
|
||||
}
|
||||
|
||||
// Firebase Docs:
|
||||
// If a callback is not specified, all callbacks for the specified eventType will be removed.
|
||||
const registrations = SyncTree.getRegistrationsByPathEvent(this.path, eventType);
|
||||
const registrations = SyncTree.getRegistrationsByPathEvent(
|
||||
this.path,
|
||||
eventType
|
||||
);
|
||||
|
||||
SyncTree.removeListenersForRegistrations(
|
||||
SyncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`),
|
||||
SyncTree.getRegistrationsByPathEvent(this.path, `${eventType}$cancelled`)
|
||||
);
|
||||
|
||||
return SyncTree.removeListenersForRegistrations(registrations);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Snapshot representation wrapper
|
||||
*/
|
||||
import { isObject, deepGet, deepExists } from './../../utils';
|
||||
import type Reference from './reference.js';
|
||||
import type Reference from './reference';
|
||||
|
||||
/**
|
||||
* @class DataSnapshot
|
||||
|
@ -39,7 +39,8 @@ export default class Snapshot {
|
|||
*/
|
||||
val(): any {
|
||||
// clone via JSON stringify/parse - prevent modification of this._value
|
||||
if (isObject(this._value) || Array.isArray(this._value)) return JSON.parse(JSON.stringify(this._value));
|
||||
if (isObject(this._value) || Array.isArray(this._value))
|
||||
return JSON.parse(JSON.stringify(this._value));
|
||||
return this._value;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,9 +14,7 @@ let transactionId = 0;
|
|||
* @returns {number}
|
||||
* @private
|
||||
*/
|
||||
const generateTransactionId = (): number => {
|
||||
return transactionId++;
|
||||
};
|
||||
const generateTransactionId = (): number => transactionId++;
|
||||
|
||||
/**
|
||||
* @class TransactionHandler
|
||||
|
@ -24,7 +22,7 @@ const generateTransactionId = (): number => {
|
|||
export default class TransactionHandler {
|
||||
_database: Database;
|
||||
_transactionListener: Function;
|
||||
_transactions: { [number]: Object }
|
||||
_transactions: { [number]: Object };
|
||||
|
||||
constructor(database: Database) {
|
||||
this._transactions = {};
|
||||
|
@ -32,7 +30,7 @@ export default class TransactionHandler {
|
|||
|
||||
this._transactionListener = SharedEventEmitter.addListener(
|
||||
getAppEventName(this._database, 'database_transaction_event'),
|
||||
this._handleTransactionEvent.bind(this),
|
||||
this._handleTransactionEvent.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -43,7 +41,12 @@ export default class TransactionHandler {
|
|||
* @param onComplete
|
||||
* @param applyLocally
|
||||
*/
|
||||
add(reference: Object, transactionUpdater: Function, onComplete?: Function, applyLocally?: boolean = false) {
|
||||
add(
|
||||
reference: Object,
|
||||
transactionUpdater: Function,
|
||||
onComplete?: Function,
|
||||
applyLocally?: boolean = false
|
||||
) {
|
||||
const id = generateTransactionId();
|
||||
|
||||
this._transactions[id] = {
|
||||
|
@ -56,7 +59,11 @@ export default class TransactionHandler {
|
|||
started: true,
|
||||
};
|
||||
|
||||
getNativeModule(this._database).transactionStart(reference.path, id, applyLocally);
|
||||
getNativeModule(this._database).transactionStart(
|
||||
reference.path,
|
||||
id,
|
||||
applyLocally
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,7 +85,10 @@ export default class TransactionHandler {
|
|||
case 'complete':
|
||||
return this._handleComplete(event);
|
||||
default:
|
||||
getLogger(this._database).warn(`Unknown transaction event type: '${event.type}'`, event);
|
||||
getLogger(this._database).warn(
|
||||
`Unknown transaction event type: '${event.type}'`,
|
||||
event
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@ -104,7 +114,10 @@ export default class TransactionHandler {
|
|||
abort = true;
|
||||
}
|
||||
|
||||
getNativeModule(this._database).transactionTryCommit(id, { value: newValue, abort });
|
||||
getNativeModule(this._database).transactionTryCommit(id, {
|
||||
value: newValue,
|
||||
abort,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,7 +150,11 @@ export default class TransactionHandler {
|
|||
if (transaction && !transaction.completed) {
|
||||
transaction.completed = true;
|
||||
try {
|
||||
transaction.onComplete(null, event.committed, Object.assign({}, event.snapshot));
|
||||
transaction.onComplete(
|
||||
null,
|
||||
event.committed,
|
||||
Object.assign({}, event.snapshot)
|
||||
);
|
||||
} finally {
|
||||
setImmediate(() => {
|
||||
delete this._transactions[event.id];
|
||||
|
|
|
@ -14,6 +14,7 @@ export default class Crashlytics extends ModuleBase {
|
|||
constructor(app: App) {
|
||||
super(app, {
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,9 +7,18 @@ import Query from './Query';
|
|||
import { firestoreAutoId } from '../../utils';
|
||||
|
||||
import type Firestore from './';
|
||||
import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types';
|
||||
import type {
|
||||
FirestoreQueryDirection,
|
||||
FirestoreQueryOperator,
|
||||
} from '../../types';
|
||||
import type FieldPath from './FieldPath';
|
||||
import type Path from './Path';
|
||||
import type { Observer, ObserverOnError, ObserverOnNext, QueryListenOptions } from './Query';
|
||||
import type {
|
||||
Observer,
|
||||
ObserverOnError,
|
||||
ObserverOnNext,
|
||||
QueryListenOptions,
|
||||
} from './Query';
|
||||
import type QuerySnapshot from './QuerySnapshot';
|
||||
|
||||
/**
|
||||
|
@ -36,13 +45,14 @@ export default class CollectionReference {
|
|||
|
||||
get parent(): DocumentReference | null {
|
||||
const parentPath = this._collectionPath.parent();
|
||||
return parentPath ? new DocumentReference(this._firestore, parentPath) : null;
|
||||
return parentPath
|
||||
? new DocumentReference(this._firestore, parentPath)
|
||||
: null;
|
||||
}
|
||||
|
||||
add(data: Object): Promise<DocumentReference> {
|
||||
const documentRef = this.doc();
|
||||
return documentRef.set(data)
|
||||
.then(() => Promise.resolve(documentRef));
|
||||
return documentRef.set(data).then(() => Promise.resolve(documentRef));
|
||||
}
|
||||
|
||||
doc(documentPath?: string): DocumentReference {
|
||||
|
@ -76,12 +86,19 @@ export default class CollectionReference {
|
|||
onSnapshot(
|
||||
optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext,
|
||||
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
|
||||
onError?: ObserverOnError,
|
||||
onError?: ObserverOnError
|
||||
): () => void {
|
||||
return this._query.onSnapshot(optionsOrObserverOrOnNext, observerOrOnNextOrOnError, onError);
|
||||
return this._query.onSnapshot(
|
||||
optionsOrObserverOrOnNext,
|
||||
observerOrOnNextOrOnError,
|
||||
onError
|
||||
);
|
||||
}
|
||||
|
||||
orderBy(fieldPath: string, directionStr?: FirestoreQueryDirection): Query {
|
||||
orderBy(
|
||||
fieldPath: string | FieldPath,
|
||||
directionStr?: FirestoreQueryDirection
|
||||
): Query {
|
||||
return this._query.orderBy(fieldPath, directionStr);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
*/
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import FieldPath from './FieldPath';
|
||||
import { mergeFieldPathData } from './utils';
|
||||
import { buildNativeMap } from './utils/serialize';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
import { getLogger } from '../../utils/log';
|
||||
|
@ -11,20 +13,23 @@ import { firestoreAutoId, isFunction, isObject, isString } from '../../utils';
|
|||
import { getNativeModule } from '../../utils/native';
|
||||
|
||||
import type Firestore from './';
|
||||
import type { FirestoreNativeDocumentSnapshot, FirestoreWriteOptions } from '../../types';
|
||||
import type {
|
||||
FirestoreNativeDocumentSnapshot,
|
||||
FirestoreWriteOptions,
|
||||
} from '../../types';
|
||||
import type Path from './Path';
|
||||
|
||||
type DocumentListenOptions = {
|
||||
includeMetadataChanges: boolean,
|
||||
}
|
||||
};
|
||||
|
||||
type ObserverOnError = (Object) => void;
|
||||
type ObserverOnNext = (DocumentSnapshot) => void;
|
||||
type ObserverOnError = Object => void;
|
||||
type ObserverOnNext = DocumentSnapshot => void;
|
||||
|
||||
type Observer = {
|
||||
error?: ObserverOnError,
|
||||
next: ObserverOnNext,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class DocumentReference
|
||||
|
@ -68,8 +73,7 @@ export default class DocumentReference {
|
|||
}
|
||||
|
||||
delete(): Promise<void> {
|
||||
return getNativeModule(this._firestore)
|
||||
.documentDelete(this.path);
|
||||
return getNativeModule(this._firestore).documentDelete(this.path);
|
||||
}
|
||||
|
||||
get(): Promise<DocumentSnapshot> {
|
||||
|
@ -79,28 +83,41 @@ export default class DocumentReference {
|
|||
}
|
||||
|
||||
onSnapshot(
|
||||
optionsOrObserverOrOnNext: DocumentListenOptions | Observer | ObserverOnNext,
|
||||
optionsOrObserverOrOnNext:
|
||||
| DocumentListenOptions
|
||||
| Observer
|
||||
| ObserverOnNext,
|
||||
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
|
||||
onError?: ObserverOnError,
|
||||
onError?: ObserverOnError
|
||||
) {
|
||||
let observer: Observer;
|
||||
let docListenOptions = {};
|
||||
// Called with: onNext, ?onError
|
||||
if (isFunction(optionsOrObserverOrOnNext)) {
|
||||
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Second argument must be a valid function.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Second argument must be a valid function.'
|
||||
);
|
||||
}
|
||||
// $FlowBug: Not coping with the overloaded method signature
|
||||
observer = {
|
||||
next: optionsOrObserverOrOnNext,
|
||||
error: observerOrOnNextOrOnError,
|
||||
};
|
||||
} else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) {
|
||||
} else if (
|
||||
optionsOrObserverOrOnNext &&
|
||||
isObject(optionsOrObserverOrOnNext)
|
||||
) {
|
||||
// Called with: Observer
|
||||
if (optionsOrObserverOrOnNext.next) {
|
||||
if (isFunction(optionsOrObserverOrOnNext.next)) {
|
||||
if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.');
|
||||
if (
|
||||
optionsOrObserverOrOnNext.error &&
|
||||
!isFunction(optionsOrObserverOrOnNext.error)
|
||||
) {
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
}
|
||||
// $FlowBug: Not coping with the overloaded method signature
|
||||
observer = {
|
||||
|
@ -108,14 +125,23 @@ export default class DocumentReference {
|
|||
error: optionsOrObserverOrOnNext.error,
|
||||
};
|
||||
} else {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
}
|
||||
} else if (optionsOrObserverOrOnNext.includeMetadataChanges) {
|
||||
} else if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
optionsOrObserverOrOnNext,
|
||||
'includeMetadataChanges'
|
||||
)
|
||||
) {
|
||||
docListenOptions = optionsOrObserverOrOnNext;
|
||||
// Called with: Options, onNext, ?onError
|
||||
if (isFunction(observerOrOnNextOrOnError)) {
|
||||
if (onError && !isFunction(onError)) {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Third argument must be a valid function.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Third argument must be a valid function.'
|
||||
);
|
||||
}
|
||||
// $FlowBug: Not coping with the overloaded method signature
|
||||
observer = {
|
||||
|
@ -123,51 +149,79 @@ export default class DocumentReference {
|
|||
error: onError,
|
||||
};
|
||||
// Called with Options, Observer
|
||||
} else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) {
|
||||
} else if (
|
||||
observerOrOnNextOrOnError &&
|
||||
isObject(observerOrOnNextOrOnError) &&
|
||||
observerOrOnNextOrOnError.next
|
||||
) {
|
||||
if (isFunction(observerOrOnNextOrOnError.next)) {
|
||||
if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Observer.error must be a valid function.');
|
||||
if (
|
||||
observerOrOnNextOrOnError.error &&
|
||||
!isFunction(observerOrOnNextOrOnError.error)
|
||||
) {
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
}
|
||||
observer = {
|
||||
next: observerOrOnNextOrOnError.next,
|
||||
error: observerOrOnNextOrOnError.error,
|
||||
};
|
||||
} else {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Observer.next must be a valid function.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Second argument must be a function or observer.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Second argument must be a function or observer.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('DocumentReference.onSnapshot failed: First argument must be a function, observer or options.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: First argument must be a function, observer or options.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('DocumentReference.onSnapshot failed: Called with invalid arguments.');
|
||||
throw new Error(
|
||||
'DocumentReference.onSnapshot failed: Called with invalid arguments.'
|
||||
);
|
||||
}
|
||||
const listenerId = firestoreAutoId();
|
||||
|
||||
const listener = (nativeDocumentSnapshot: FirestoreNativeDocumentSnapshot) => {
|
||||
const documentSnapshot = new DocumentSnapshot(this.firestore, nativeDocumentSnapshot);
|
||||
const listener = (
|
||||
nativeDocumentSnapshot: FirestoreNativeDocumentSnapshot
|
||||
) => {
|
||||
const documentSnapshot = new DocumentSnapshot(
|
||||
this.firestore,
|
||||
nativeDocumentSnapshot
|
||||
);
|
||||
observer.next(documentSnapshot);
|
||||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`),
|
||||
listener,
|
||||
listener
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (observer.error) {
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`),
|
||||
observer.error,
|
||||
getAppEventName(
|
||||
this._firestore,
|
||||
`onDocumentSnapshotError:${listenerId}`
|
||||
),
|
||||
observer.error
|
||||
);
|
||||
}
|
||||
|
||||
// Add the native listener
|
||||
getNativeModule(this._firestore)
|
||||
.documentOnSnapshot(this.path, listenerId, docListenOptions);
|
||||
getNativeModule(this._firestore).documentOnSnapshot(
|
||||
this.path,
|
||||
listenerId,
|
||||
docListenOptions
|
||||
);
|
||||
|
||||
// Return an unsubscribe method
|
||||
return this._offDocumentSnapshot.bind(this, listenerId, listener);
|
||||
|
@ -175,32 +229,47 @@ export default class DocumentReference {
|
|||
|
||||
set(data: Object, writeOptions?: FirestoreWriteOptions): Promise<void> {
|
||||
const nativeData = buildNativeMap(data);
|
||||
return getNativeModule(this._firestore)
|
||||
.documentSet(this.path, nativeData, writeOptions);
|
||||
return getNativeModule(this._firestore).documentSet(
|
||||
this.path,
|
||||
nativeData,
|
||||
writeOptions
|
||||
);
|
||||
}
|
||||
|
||||
update(...args: any[]): Promise<void> {
|
||||
let data = {};
|
||||
if (args.length === 1) {
|
||||
if (!isObject(args[0])) {
|
||||
throw new Error('DocumentReference.update failed: If using a single argument, it must be an object.');
|
||||
throw new Error(
|
||||
'DocumentReference.update failed: If using a single argument, it must be an object.'
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
data = args[0];
|
||||
} else if (args.length % 2 === 1) {
|
||||
throw new Error('DocumentReference.update failed: Must have either a single object argument, or equal numbers of key/value pairs.');
|
||||
throw new Error(
|
||||
'DocumentReference.update failed: Must have either a single object argument, or equal numbers of key/value pairs.'
|
||||
);
|
||||
} else {
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
const key = args[i];
|
||||
const value = args[i + 1];
|
||||
if (!isString(key)) {
|
||||
throw new Error(`DocumentReference.update failed: Argument at index ${i} must be a string`);
|
||||
}
|
||||
if (isString(key)) {
|
||||
data[key] = value;
|
||||
} else if (key instanceof FieldPath) {
|
||||
data = mergeFieldPathData(data, key._segments, value);
|
||||
} else {
|
||||
throw new Error(
|
||||
`DocumentReference.update failed: Argument at index ${i} must be a string or FieldPath`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
const nativeData = buildNativeMap(data);
|
||||
return getNativeModule(this._firestore)
|
||||
.documentUpdate(this.path, nativeData);
|
||||
return getNativeModule(this._firestore).documentUpdate(
|
||||
this.path,
|
||||
nativeData
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,9 +282,14 @@ export default class DocumentReference {
|
|||
*/
|
||||
_offDocumentSnapshot(listenerId: string, listener: Function) {
|
||||
getLogger(this._firestore).info('Removing onDocumentSnapshot listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`), listener);
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`), listener);
|
||||
getNativeModule(this._firestore)
|
||||
.documentOffSnapshot(this.path, listenerId);
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this._firestore, `onDocumentSnapshot:${listenerId}`),
|
||||
listener
|
||||
);
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this._firestore, `onDocumentSnapshotError:${listenerId}`),
|
||||
listener
|
||||
);
|
||||
getNativeModule(this._firestore).documentOffSnapshot(this.path, listenerId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,11 +3,27 @@
|
|||
* DocumentSnapshot representation wrapper
|
||||
*/
|
||||
import DocumentReference from './DocumentReference';
|
||||
import FieldPath from './FieldPath';
|
||||
import Path from './Path';
|
||||
import { isObject } from '../../utils';
|
||||
import { parseNativeMap } from './utils/serialize';
|
||||
|
||||
import type Firestore from './';
|
||||
import type { FirestoreNativeDocumentSnapshot, FirestoreSnapshotMetadata } from '../../types';
|
||||
import type {
|
||||
FirestoreNativeDocumentSnapshot,
|
||||
FirestoreSnapshotMetadata,
|
||||
} from '../../types';
|
||||
|
||||
const extractFieldPathData = (data: Object | void, segments: string[]): any => {
|
||||
if (!data || !isObject(data)) {
|
||||
return undefined;
|
||||
}
|
||||
const pathValue = data[segments[0]];
|
||||
if (segments.length === 1) {
|
||||
return pathValue;
|
||||
}
|
||||
return extractFieldPathData(pathValue, segments.slice(1));
|
||||
};
|
||||
|
||||
/**
|
||||
* @class DocumentSnapshot
|
||||
|
@ -17,10 +33,16 @@ export default class DocumentSnapshot {
|
|||
_metadata: FirestoreSnapshotMetadata;
|
||||
_ref: DocumentReference;
|
||||
|
||||
constructor(firestore: Firestore, nativeData: FirestoreNativeDocumentSnapshot) {
|
||||
constructor(
|
||||
firestore: Firestore,
|
||||
nativeData: FirestoreNativeDocumentSnapshot
|
||||
) {
|
||||
this._data = parseNativeMap(firestore, nativeData.data);
|
||||
this._metadata = nativeData.metadata;
|
||||
this._ref = new DocumentReference(firestore, Path.fromName(nativeData.path));
|
||||
this._ref = new DocumentReference(
|
||||
firestore,
|
||||
Path.fromName(nativeData.path)
|
||||
);
|
||||
}
|
||||
|
||||
get exists(): boolean {
|
||||
|
@ -43,7 +65,10 @@ export default class DocumentSnapshot {
|
|||
return this._data;
|
||||
}
|
||||
|
||||
get(fieldPath: string): any {
|
||||
get(fieldPath: string | FieldPath): any {
|
||||
if (fieldPath instanceof FieldPath) {
|
||||
return extractFieldPathData(this._data, fieldPath._segments);
|
||||
}
|
||||
return this._data ? this._data[fieldPath] : undefined;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* @flow
|
||||
* FieldPath representation wrapper
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class FieldPath
|
||||
*/
|
||||
export default class FieldPath {
|
||||
_segments: string[];
|
||||
|
||||
constructor(...segments: string[]) {
|
||||
// TODO: Validation
|
||||
this._segments = segments;
|
||||
}
|
||||
|
||||
static documentId(): FieldPath {
|
||||
return DOCUMENT_ID;
|
||||
}
|
||||
}
|
||||
|
||||
export const DOCUMENT_ID = new FieldPath('__name__');
|
|
@ -48,7 +48,7 @@ export default class Path {
|
|||
*
|
||||
* @package
|
||||
*/
|
||||
static fromName(name): Path {
|
||||
static fromName(name: string): Path {
|
||||
const parts = name.split('/');
|
||||
|
||||
if (parts.length === 0) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Query representation wrapper
|
||||
*/
|
||||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
import FieldPath from './FieldPath';
|
||||
import QuerySnapshot from './QuerySnapshot';
|
||||
import { buildNativeArray, buildTypeMap } from './utils/serialize';
|
||||
import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
||||
|
@ -11,7 +12,10 @@ import { firestoreAutoId, isFunction, isObject } from '../../utils';
|
|||
import { getNativeModule } from '../../utils/native';
|
||||
|
||||
import type Firestore from './';
|
||||
import type { FirestoreQueryDirection, FirestoreQueryOperator } from '../../types';
|
||||
import type {
|
||||
FirestoreQueryDirection,
|
||||
FirestoreQueryOperator,
|
||||
} from '../../types';
|
||||
import type Path from './Path';
|
||||
|
||||
const DIRECTIONS: { [FirestoreQueryDirection]: string } = {
|
||||
|
@ -30,15 +34,20 @@ const OPERATORS: { [FirestoreQueryOperator]: string } = {
|
|||
'<=': 'LESS_THAN_OR_EQUAL',
|
||||
};
|
||||
|
||||
type FieldFilter = {
|
||||
fieldPath: string,
|
||||
type NativeFieldPath = {|
|
||||
elements?: string[],
|
||||
string?: string,
|
||||
type: 'fieldpath' | 'string',
|
||||
|};
|
||||
type FieldFilter = {|
|
||||
fieldPath: NativeFieldPath,
|
||||
operator: string,
|
||||
value: any,
|
||||
}
|
||||
type FieldOrder = {
|
||||
|};
|
||||
type FieldOrder = {|
|
||||
direction: string,
|
||||
fieldPath: string,
|
||||
}
|
||||
fieldPath: NativeFieldPath,
|
||||
|};
|
||||
type QueryOptions = {
|
||||
endAt?: any[],
|
||||
endBefore?: any[],
|
||||
|
@ -47,20 +56,35 @@ type QueryOptions = {
|
|||
selectFields?: string[],
|
||||
startAfter?: any[],
|
||||
startAt?: any[],
|
||||
}
|
||||
};
|
||||
|
||||
export type QueryListenOptions = {
|
||||
export type QueryListenOptions = {|
|
||||
includeDocumentMetadataChanges: boolean,
|
||||
includeQueryMetadataChanges: boolean,
|
||||
}
|
||||
|};
|
||||
|
||||
export type ObserverOnError = (Object) => void;
|
||||
export type ObserverOnNext = (QuerySnapshot) => void;
|
||||
export type ObserverOnError = Object => void;
|
||||
export type ObserverOnNext = QuerySnapshot => void;
|
||||
|
||||
export type Observer = {
|
||||
error?: ObserverOnError,
|
||||
next: ObserverOnNext,
|
||||
}
|
||||
};
|
||||
|
||||
const buildNativeFieldPath = (
|
||||
fieldPath: string | FieldPath
|
||||
): NativeFieldPath => {
|
||||
if (fieldPath instanceof FieldPath) {
|
||||
return {
|
||||
elements: fieldPath._segments,
|
||||
type: 'fieldpath',
|
||||
};
|
||||
}
|
||||
return {
|
||||
string: fieldPath,
|
||||
type: 'string',
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Query
|
||||
|
@ -76,10 +100,9 @@ export default class Query {
|
|||
constructor(
|
||||
firestore: Firestore,
|
||||
path: Path,
|
||||
fieldFilters?:
|
||||
FieldFilter[],
|
||||
fieldFilters?: FieldFilter[],
|
||||
fieldOrders?: FieldOrder[],
|
||||
queryOptions?: QueryOptions,
|
||||
queryOptions?: QueryOptions
|
||||
) {
|
||||
this._fieldFilters = fieldFilters || [];
|
||||
this._fieldOrders = fieldOrders || [];
|
||||
|
@ -103,7 +126,7 @@ export default class Query {
|
|||
this._referencePath,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
options,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -118,7 +141,7 @@ export default class Query {
|
|||
this._referencePath,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
options,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -128,7 +151,7 @@ export default class Query {
|
|||
this._referencePath.relativeName,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
this._queryOptions
|
||||
)
|
||||
.then(nativeData => new QuerySnapshot(this._firestore, this, nativeData));
|
||||
}
|
||||
|
@ -146,33 +169,43 @@ export default class Query {
|
|||
this._referencePath,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
options,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
onSnapshot(
|
||||
optionsOrObserverOrOnNext: QueryListenOptions | Observer | ObserverOnNext,
|
||||
observerOrOnNextOrOnError?: Observer | ObserverOnNext | ObserverOnError,
|
||||
onError?: ObserverOnError,
|
||||
onError?: ObserverOnError
|
||||
) {
|
||||
let observer: Observer;
|
||||
let queryListenOptions = {};
|
||||
// Called with: onNext, ?onError
|
||||
if (isFunction(optionsOrObserverOrOnNext)) {
|
||||
if (observerOrOnNextOrOnError && !isFunction(observerOrOnNextOrOnError)) {
|
||||
throw new Error('Query.onSnapshot failed: Second argument must be a valid function.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Second argument must be a valid function.'
|
||||
);
|
||||
}
|
||||
// $FlowBug: Not coping with the overloaded method signature
|
||||
observer = {
|
||||
next: optionsOrObserverOrOnNext,
|
||||
error: observerOrOnNextOrOnError,
|
||||
};
|
||||
} else if (optionsOrObserverOrOnNext && isObject(optionsOrObserverOrOnNext)) {
|
||||
} else if (
|
||||
optionsOrObserverOrOnNext &&
|
||||
isObject(optionsOrObserverOrOnNext)
|
||||
) {
|
||||
// Called with: Observer
|
||||
if (optionsOrObserverOrOnNext.next) {
|
||||
if (isFunction(optionsOrObserverOrOnNext.next)) {
|
||||
if (optionsOrObserverOrOnNext.error && !isFunction(optionsOrObserverOrOnNext.error)) {
|
||||
throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.');
|
||||
if (
|
||||
optionsOrObserverOrOnNext.error &&
|
||||
!isFunction(optionsOrObserverOrOnNext.error)
|
||||
) {
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
}
|
||||
// $FlowBug: Not coping with the overloaded method signature
|
||||
observer = {
|
||||
|
@ -180,14 +213,27 @@ export default class Query {
|
|||
error: optionsOrObserverOrOnNext.error,
|
||||
};
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
}
|
||||
} else if (optionsOrObserverOrOnNext.includeDocumentMetadataChanges || optionsOrObserverOrOnNext.includeQueryMetadataChanges) {
|
||||
} else if (
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
optionsOrObserverOrOnNext,
|
||||
'includeDocumentMetadataChanges'
|
||||
) ||
|
||||
Object.prototype.hasOwnProperty.call(
|
||||
optionsOrObserverOrOnNext,
|
||||
'includeQueryMetadataChanges'
|
||||
)
|
||||
) {
|
||||
queryListenOptions = optionsOrObserverOrOnNext;
|
||||
// Called with: Options, onNext, ?onError
|
||||
if (isFunction(observerOrOnNextOrOnError)) {
|
||||
if (onError && !isFunction(onError)) {
|
||||
throw new Error('Query.onSnapshot failed: Third argument must be a valid function.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Third argument must be a valid function.'
|
||||
);
|
||||
}
|
||||
// $FlowBug: Not coping with the overloaded method signature
|
||||
observer = {
|
||||
|
@ -195,76 +241,101 @@ export default class Query {
|
|||
error: onError,
|
||||
};
|
||||
// Called with Options, Observer
|
||||
} else if (observerOrOnNextOrOnError && isObject(observerOrOnNextOrOnError) && observerOrOnNextOrOnError.next) {
|
||||
} else if (
|
||||
observerOrOnNextOrOnError &&
|
||||
isObject(observerOrOnNextOrOnError) &&
|
||||
observerOrOnNextOrOnError.next
|
||||
) {
|
||||
if (isFunction(observerOrOnNextOrOnError.next)) {
|
||||
if (observerOrOnNextOrOnError.error && !isFunction(observerOrOnNextOrOnError.error)) {
|
||||
throw new Error('Query.onSnapshot failed: Observer.error must be a valid function.');
|
||||
if (
|
||||
observerOrOnNextOrOnError.error &&
|
||||
!isFunction(observerOrOnNextOrOnError.error)
|
||||
) {
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Observer.error must be a valid function.'
|
||||
);
|
||||
}
|
||||
observer = {
|
||||
next: observerOrOnNextOrOnError.next,
|
||||
error: observerOrOnNextOrOnError.error,
|
||||
};
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Observer.next must be a valid function.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Observer.next must be a valid function.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Second argument must be a function or observer.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Second argument must be a function or observer.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: First argument must be a function, observer or options.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: First argument must be a function, observer or options.'
|
||||
);
|
||||
}
|
||||
} else {
|
||||
throw new Error('Query.onSnapshot failed: Called with invalid arguments.');
|
||||
throw new Error(
|
||||
'Query.onSnapshot failed: Called with invalid arguments.'
|
||||
);
|
||||
}
|
||||
const listenerId = firestoreAutoId();
|
||||
|
||||
const listener = (nativeQuerySnapshot) => {
|
||||
const querySnapshot = new QuerySnapshot(this._firestore, this, nativeQuerySnapshot);
|
||||
const listener = nativeQuerySnapshot => {
|
||||
const querySnapshot = new QuerySnapshot(
|
||||
this._firestore,
|
||||
this,
|
||||
nativeQuerySnapshot
|
||||
);
|
||||
observer.next(querySnapshot);
|
||||
};
|
||||
|
||||
// Listen to snapshot events
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`),
|
||||
listener,
|
||||
listener
|
||||
);
|
||||
|
||||
// Listen for snapshot error events
|
||||
if (observer.error) {
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`),
|
||||
observer.error,
|
||||
observer.error
|
||||
);
|
||||
}
|
||||
|
||||
// Add the native listener
|
||||
getNativeModule(this._firestore)
|
||||
.collectionOnSnapshot(
|
||||
getNativeModule(this._firestore).collectionOnSnapshot(
|
||||
this._referencePath.relativeName,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
listenerId,
|
||||
queryListenOptions,
|
||||
queryListenOptions
|
||||
);
|
||||
|
||||
// Return an unsubscribe method
|
||||
return this._offCollectionSnapshot.bind(this, listenerId, listener);
|
||||
}
|
||||
|
||||
orderBy(fieldPath: string, directionStr?: FirestoreQueryDirection = 'asc'): Query {
|
||||
orderBy(
|
||||
fieldPath: string | FieldPath,
|
||||
directionStr?: FirestoreQueryDirection = 'asc'
|
||||
): Query {
|
||||
// TODO: Validation
|
||||
// validate.isFieldPath('fieldPath', fieldPath);
|
||||
// validate.isOptionalFieldOrder('directionStr', directionStr);
|
||||
|
||||
if (this._queryOptions.startAt || this._queryOptions.endAt) {
|
||||
throw new Error('Cannot specify an orderBy() constraint after calling ' +
|
||||
'startAt(), startAfter(), endBefore() or endAt().');
|
||||
throw new Error(
|
||||
'Cannot specify an orderBy() constraint after calling ' +
|
||||
'startAt(), startAfter(), endBefore() or endAt().'
|
||||
);
|
||||
}
|
||||
|
||||
const newOrder = {
|
||||
const newOrder: FieldOrder = {
|
||||
direction: DIRECTIONS[directionStr],
|
||||
fieldPath,
|
||||
fieldPath: buildNativeFieldPath(fieldPath),
|
||||
};
|
||||
const combinedOrders = this._fieldOrders.concat(newOrder);
|
||||
return new Query(
|
||||
|
@ -272,7 +343,7 @@ export default class Query {
|
|||
this._referencePath,
|
||||
this._fieldFilters,
|
||||
combinedOrders,
|
||||
this._queryOptions,
|
||||
this._queryOptions
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -287,7 +358,7 @@ export default class Query {
|
|||
this._referencePath,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
options,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -302,17 +373,21 @@ export default class Query {
|
|||
this._referencePath,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
options,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
where(fieldPath: string, opStr: FirestoreQueryOperator, value: any): Query {
|
||||
where(
|
||||
fieldPath: string | FieldPath,
|
||||
opStr: FirestoreQueryOperator,
|
||||
value: any
|
||||
): Query {
|
||||
// TODO: Validation
|
||||
// validate.isFieldPath('fieldPath', fieldPath);
|
||||
// validate.isFieldFilter('fieldFilter', opStr, value);
|
||||
const nativeValue = buildTypeMap(value);
|
||||
const newFilter = {
|
||||
fieldPath,
|
||||
const newFilter: FieldFilter = {
|
||||
fieldPath: buildNativeFieldPath(fieldPath),
|
||||
operator: OPERATORS[opStr],
|
||||
value: nativeValue,
|
||||
};
|
||||
|
@ -322,7 +397,7 @@ export default class Query {
|
|||
this._referencePath,
|
||||
combinedFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
this._queryOptions
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -333,12 +408,23 @@ export default class Query {
|
|||
_buildOrderByOption(snapshotOrVarArgs: any[]) {
|
||||
// TODO: Validation
|
||||
let values;
|
||||
if (snapshotOrVarArgs.length === 1 && snapshotOrVarArgs[0] instanceof DocumentSnapshot) {
|
||||
const docSnapshot = snapshotOrVarArgs[0];
|
||||
if (
|
||||
snapshotOrVarArgs.length === 1 &&
|
||||
snapshotOrVarArgs[0] instanceof DocumentSnapshot
|
||||
) {
|
||||
const docSnapshot: DocumentSnapshot = snapshotOrVarArgs[0];
|
||||
values = [];
|
||||
for (let i = 0; i < this._fieldOrders.length; i++) {
|
||||
const fieldOrder = this._fieldOrders[i];
|
||||
values.push(docSnapshot.get(fieldOrder.fieldPath));
|
||||
if (
|
||||
fieldOrder.fieldPath.type === 'string' &&
|
||||
fieldOrder.fieldPath.string
|
||||
) {
|
||||
values.push(docSnapshot.get(fieldOrder.fieldPath.string));
|
||||
} else if (fieldOrder.fieldPath.fieldpath) {
|
||||
const fieldPath = new FieldPath(...fieldOrder.fieldPath.fieldpath);
|
||||
values.push(docSnapshot.get(fieldPath));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
values = snapshotOrVarArgs;
|
||||
|
@ -353,15 +439,20 @@ export default class Query {
|
|||
*/
|
||||
_offCollectionSnapshot(listenerId: string, listener: Function) {
|
||||
getLogger(this._firestore).info('Removing onQuerySnapshot listener');
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`), listener);
|
||||
SharedEventEmitter.removeListener(getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`), listener);
|
||||
getNativeModule(this._firestore)
|
||||
.collectionOffSnapshot(
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this._firestore, `onQuerySnapshot:${listenerId}`),
|
||||
listener
|
||||
);
|
||||
SharedEventEmitter.removeListener(
|
||||
getAppEventName(this._firestore, `onQuerySnapshotError:${listenerId}`),
|
||||
listener
|
||||
);
|
||||
getNativeModule(this._firestore).collectionOffSnapshot(
|
||||
this._referencePath.relativeName,
|
||||
this._fieldFilters,
|
||||
this._fieldOrders,
|
||||
this._queryOptions,
|
||||
listenerId,
|
||||
listenerId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,18 @@ import DocumentChange from './DocumentChange';
|
|||
import DocumentSnapshot from './DocumentSnapshot';
|
||||
|
||||
import type Firestore from './';
|
||||
import type { FirestoreNativeDocumentChange, FirestoreNativeDocumentSnapshot, FirestoreSnapshotMetadata } from '../../types';
|
||||
import type {
|
||||
FirestoreNativeDocumentChange,
|
||||
FirestoreNativeDocumentSnapshot,
|
||||
FirestoreSnapshotMetadata,
|
||||
} from '../../types';
|
||||
import type Query from './Query';
|
||||
|
||||
type QuerySnapshotNativeData = {
|
||||
changes: FirestoreNativeDocumentChange[],
|
||||
documents: FirestoreNativeDocumentSnapshot[],
|
||||
metadata: FirestoreSnapshotMetadata,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class QuerySnapshot
|
||||
|
@ -24,9 +28,17 @@ export default class QuerySnapshot {
|
|||
_metadata: FirestoreSnapshotMetadata;
|
||||
_query: Query;
|
||||
|
||||
constructor(firestore: Firestore, query: Query, nativeData: QuerySnapshotNativeData) {
|
||||
this._changes = nativeData.changes.map(change => new DocumentChange(firestore, change));
|
||||
this._docs = nativeData.documents.map(doc => new DocumentSnapshot(firestore, doc));
|
||||
constructor(
|
||||
firestore: Firestore,
|
||||
query: Query,
|
||||
nativeData: QuerySnapshotNativeData
|
||||
) {
|
||||
this._changes = nativeData.changes.map(
|
||||
change => new DocumentChange(firestore, change)
|
||||
);
|
||||
this._docs = nativeData.documents.map(
|
||||
doc => new DocumentSnapshot(firestore, doc)
|
||||
);
|
||||
this._metadata = nativeData.metadata;
|
||||
this._query = query;
|
||||
}
|
||||
|
@ -59,7 +71,7 @@ export default class QuerySnapshot {
|
|||
// TODO: Validation
|
||||
// validate.isFunction('callback', callback);
|
||||
|
||||
this._docs.forEach((doc) => {
|
||||
this._docs.forEach(doc => {
|
||||
callback(doc);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
* @flow
|
||||
* WriteBatch representation wrapper
|
||||
*/
|
||||
import FieldPath from './FieldPath';
|
||||
import { mergeFieldPathData } from './utils';
|
||||
import { buildNativeMap } from './utils/serialize';
|
||||
import { isObject, isString } from '../../utils';
|
||||
import { getNativeModule } from '../../utils/native';
|
||||
|
@ -15,7 +17,7 @@ type DocumentWrite = {
|
|||
options?: Object,
|
||||
path: string,
|
||||
type: 'DELETE' | 'SET' | 'UPDATE',
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class WriteBatch
|
||||
|
@ -45,7 +47,11 @@ export default class WriteBatch {
|
|||
return this;
|
||||
}
|
||||
|
||||
set(docRef: DocumentReference, data: Object, writeOptions?: FirestoreWriteOptions) {
|
||||
set(
|
||||
docRef: DocumentReference,
|
||||
data: Object,
|
||||
writeOptions?: FirestoreWriteOptions
|
||||
) {
|
||||
// TODO: Validation
|
||||
// validate.isDocumentReference('docRef', docRef);
|
||||
// validate.isDocument('data', data);
|
||||
|
@ -67,19 +73,29 @@ export default class WriteBatch {
|
|||
let data = {};
|
||||
if (args.length === 1) {
|
||||
if (!isObject(args[0])) {
|
||||
throw new Error('DocumentReference.update failed: If using two arguments, the second must be an object.');
|
||||
throw new Error(
|
||||
'WriteBatch.update failed: If using two arguments, the second must be an object.'
|
||||
);
|
||||
}
|
||||
// eslint-disable-next-line prefer-destructuring
|
||||
data = args[0];
|
||||
} else if (args.length % 2 === 1) {
|
||||
throw new Error('DocumentReference.update failed: Must have a document reference, followed by either a single object argument, or equal numbers of key/value pairs.');
|
||||
throw new Error(
|
||||
'WriteBatch.update failed: Must have a document reference, followed by either a single object argument, or equal numbers of key/value pairs.'
|
||||
);
|
||||
} else {
|
||||
for (let i = 0; i < args.length; i += 2) {
|
||||
const key = args[i];
|
||||
const value = args[i + 1];
|
||||
if (!isString(key)) {
|
||||
throw new Error(`DocumentReference.update failed: Argument at index ${i + 1} must be a string`);
|
||||
}
|
||||
if (isString(key)) {
|
||||
data[key] = value;
|
||||
} else if (key instanceof FieldPath) {
|
||||
data = mergeFieldPathData(data, key._segments, value);
|
||||
} else {
|
||||
throw new Error(
|
||||
`WriteBatch.update failed: Argument at index ${i} must be a string or FieldPath`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ import { getAppEventName, SharedEventEmitter } from '../../utils/events';
|
|||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import CollectionReference from './CollectionReference';
|
||||
import DocumentReference from './DocumentReference';
|
||||
import FieldPath from './FieldPath';
|
||||
import FieldValue from './FieldValue';
|
||||
import GeoPoint from './GeoPoint';
|
||||
import Path from './Path';
|
||||
|
@ -24,7 +25,7 @@ type CollectionSyncEvent = {
|
|||
error?: Object,
|
||||
listenerId: string,
|
||||
path: string,
|
||||
}
|
||||
};
|
||||
|
||||
type DocumentSyncEvent = {
|
||||
appName: string,
|
||||
|
@ -32,7 +33,7 @@ type DocumentSyncEvent = {
|
|||
error?: Object,
|
||||
listenerId: string,
|
||||
path: string,
|
||||
}
|
||||
};
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
'firestore_collection_sync_event',
|
||||
|
@ -52,6 +53,7 @@ export default class Firestore extends ModuleBase {
|
|||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: true,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
this._referencePath = new Path([]);
|
||||
|
@ -60,14 +62,14 @@ export default class Firestore extends ModuleBase {
|
|||
// sub to internal native event - this fans out to
|
||||
// public event name: onCollectionSnapshot
|
||||
getAppEventName(this, 'firestore_collection_sync_event'),
|
||||
this._onCollectionSyncEvent.bind(this),
|
||||
this._onCollectionSyncEvent.bind(this)
|
||||
);
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
// sub to internal native event - this fans out to
|
||||
// public event name: onDocumentSnapshot
|
||||
getAppEventName(this, 'firestore_document_sync_event'),
|
||||
this._onDocumentSyncEvent.bind(this),
|
||||
this._onDocumentSyncEvent.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -112,7 +114,12 @@ export default class Firestore extends ModuleBase {
|
|||
}
|
||||
|
||||
setLogLevel(): void {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD('firestore', 'setLogLevel'));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_UNSUPPORTED_MODULE_METHOD(
|
||||
'firestore',
|
||||
'setLogLevel'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
settings(): void {
|
||||
|
@ -126,9 +133,15 @@ export default class Firestore extends ModuleBase {
|
|||
*/
|
||||
_onCollectionSyncEvent(event: CollectionSyncEvent) {
|
||||
if (event.error) {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onQuerySnapshotError:${event.listenerId}`), event.error);
|
||||
SharedEventEmitter.emit(
|
||||
getAppEventName(this, `onQuerySnapshotError:${event.listenerId}`),
|
||||
event.error
|
||||
);
|
||||
} else {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onQuerySnapshot:${event.listenerId}`), event.querySnapshot);
|
||||
SharedEventEmitter.emit(
|
||||
getAppEventName(this, `onQuerySnapshot:${event.listenerId}`),
|
||||
event.querySnapshot
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -139,14 +152,21 @@ export default class Firestore extends ModuleBase {
|
|||
*/
|
||||
_onDocumentSyncEvent(event: DocumentSyncEvent) {
|
||||
if (event.error) {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onDocumentSnapshotError:${event.listenerId}`), event.error);
|
||||
SharedEventEmitter.emit(
|
||||
getAppEventName(this, `onDocumentSnapshotError:${event.listenerId}`),
|
||||
event.error
|
||||
);
|
||||
} else {
|
||||
SharedEventEmitter.emit(getAppEventName(this, `onDocumentSnapshot:${event.listenerId}`), event.documentSnapshot);
|
||||
SharedEventEmitter.emit(
|
||||
getAppEventName(this, `onDocumentSnapshot:${event.listenerId}`),
|
||||
event.documentSnapshot
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const statics = {
|
||||
FieldPath,
|
||||
FieldValue,
|
||||
GeoPoint,
|
||||
enableLogging(enabled: boolean) {
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @flow
|
||||
*/
|
||||
|
||||
const buildFieldPathData = (segments: string[], value: any): Object => {
|
||||
if (segments.length === 1) {
|
||||
return {
|
||||
[segments[0]]: value,
|
||||
};
|
||||
}
|
||||
return {
|
||||
[segments[0]]: buildFieldPathData(segments.slice(1), value),
|
||||
};
|
||||
};
|
||||
|
||||
// eslint-disable-next-line import/prefer-default-export
|
||||
export const mergeFieldPathData = (
|
||||
data: Object,
|
||||
segments: string[],
|
||||
value: any
|
||||
): Object => {
|
||||
if (segments.length === 1) {
|
||||
return {
|
||||
...data,
|
||||
[segments[0]]: value,
|
||||
};
|
||||
} else if (data[segments[0]]) {
|
||||
return {
|
||||
...data,
|
||||
[segments[0]]: mergeFieldPathData(
|
||||
data[segments[0]],
|
||||
segments.slice(1),
|
||||
value
|
||||
),
|
||||
};
|
||||
}
|
||||
return {
|
||||
...data,
|
||||
[segments[0]]: buildFieldPathData(segments.slice(1), value),
|
||||
};
|
||||
};
|
|
@ -3,7 +3,11 @@
|
|||
*/
|
||||
|
||||
import DocumentReference from '../DocumentReference';
|
||||
import { DELETE_FIELD_VALUE, SERVER_TIMESTAMP_FIELD_VALUE } from '../FieldValue';
|
||||
import { DOCUMENT_ID } from '../FieldPath';
|
||||
import {
|
||||
DELETE_FIELD_VALUE,
|
||||
SERVER_TIMESTAMP_FIELD_VALUE,
|
||||
} from '../FieldValue';
|
||||
import GeoPoint from '../GeoPoint';
|
||||
import Path from '../Path';
|
||||
import { typeOf } from '../../../utils';
|
||||
|
@ -17,10 +21,12 @@ import type { FirestoreTypeMap } from '../../../types';
|
|||
* for transmission to the native side
|
||||
*/
|
||||
|
||||
export const buildNativeMap = (data: Object): { [string]: FirestoreTypeMap } => {
|
||||
export const buildNativeMap = (
|
||||
data: Object
|
||||
): { [string]: FirestoreTypeMap } => {
|
||||
const nativeData = {};
|
||||
if (data) {
|
||||
Object.keys(data).forEach((key) => {
|
||||
Object.keys(data).forEach(key => {
|
||||
const typeMap = buildTypeMap(data[key]);
|
||||
if (typeMap) {
|
||||
nativeData[key] = typeMap;
|
||||
|
@ -33,7 +39,7 @@ export const buildNativeMap = (data: Object): { [string]: FirestoreTypeMap } =>
|
|||
export const buildNativeArray = (array: Object[]): FirestoreTypeMap[] => {
|
||||
const nativeArray = [];
|
||||
if (array) {
|
||||
array.forEach((value) => {
|
||||
array.forEach(value => {
|
||||
const typeMap = buildTypeMap(value);
|
||||
if (typeMap) {
|
||||
nativeArray.push(typeMap);
|
||||
|
@ -60,6 +66,11 @@ export const buildTypeMap = (value: any): FirestoreTypeMap | null => {
|
|||
type: 'fieldvalue',
|
||||
value: 'timestamp',
|
||||
};
|
||||
} else if (value === DOCUMENT_ID) {
|
||||
return {
|
||||
type: 'documentid',
|
||||
value: null,
|
||||
};
|
||||
} else if (type === 'boolean' || type === 'number' || type === 'string') {
|
||||
return {
|
||||
type,
|
||||
|
@ -104,21 +115,27 @@ export const buildTypeMap = (value: any): FirestoreTypeMap | null => {
|
|||
* side and converts to the correct Firestore JS types
|
||||
*/
|
||||
|
||||
export const parseNativeMap = (firestore: Firestore, nativeData: { [string]: FirestoreTypeMap }): Object | void => {
|
||||
export const parseNativeMap = (
|
||||
firestore: Firestore,
|
||||
nativeData: { [string]: FirestoreTypeMap }
|
||||
): Object | void => {
|
||||
let data;
|
||||
if (nativeData) {
|
||||
data = {};
|
||||
Object.keys(nativeData).forEach((key) => {
|
||||
Object.keys(nativeData).forEach(key => {
|
||||
data[key] = parseTypeMap(firestore, nativeData[key]);
|
||||
});
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const parseNativeArray = (firestore: Firestore, nativeArray: FirestoreTypeMap[]): any[] => {
|
||||
const parseNativeArray = (
|
||||
firestore: Firestore,
|
||||
nativeArray: FirestoreTypeMap[]
|
||||
): any[] => {
|
||||
const array = [];
|
||||
if (nativeArray) {
|
||||
nativeArray.forEach((typeMap) => {
|
||||
nativeArray.forEach(typeMap => {
|
||||
array.push(parseTypeMap(firestore, typeMap));
|
||||
});
|
||||
}
|
||||
|
|
|
@ -13,9 +13,7 @@ const EVENT_TYPE = {
|
|||
Link: 'dynamic_link_received',
|
||||
};
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
EVENT_TYPE.Link,
|
||||
];
|
||||
const NATIVE_EVENTS = [EVENT_TYPE.Link];
|
||||
|
||||
export const MODULE_NAME = 'RNFirebaseLinks';
|
||||
export const NAMESPACE = 'links';
|
||||
|
@ -59,10 +57,16 @@ function checkForMandatoryParameters(parameters: Object): void {
|
|||
if (!isString(parameters.link)) {
|
||||
throw new Error('No link was specified.');
|
||||
}
|
||||
if (isObject(parameters.androidInfo) && !isString(parameters.androidInfo.androidPackageName)) {
|
||||
if (
|
||||
isObject(parameters.androidInfo) &&
|
||||
!isString(parameters.androidInfo.androidPackageName)
|
||||
) {
|
||||
throw new Error('No androidPackageName was specified.');
|
||||
}
|
||||
if (isObject(parameters.iosInfo) && !isString(parameters.iosInfo.iosBundleId)) {
|
||||
if (
|
||||
isObject(parameters.iosInfo) &&
|
||||
!isString(parameters.iosInfo.iosBundleId)
|
||||
) {
|
||||
throw new Error('No iosBundleId was specified.');
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +79,7 @@ export default class Links extends ModuleBase {
|
|||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
@ -97,7 +102,10 @@ export default class Links extends ModuleBase {
|
|||
* @returns {Function}
|
||||
*/
|
||||
onLink(listener: Function): () => any {
|
||||
const rnListener = SharedEventEmitter.addListener(EVENT_TYPE.Link, listener);
|
||||
const rnListener = SharedEventEmitter.addListener(
|
||||
EVENT_TYPE.Link,
|
||||
listener
|
||||
);
|
||||
return () => rnListener.remove();
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,9 @@ export default class RemoteMessage {
|
|||
id: generatePushID(),
|
||||
ttl: 3600,
|
||||
// add the googleapis sender id part if not already added.
|
||||
sender: `${sender}`.includes('@') ? sender : `${sender}@gcm.googleapis.com`,
|
||||
sender: `${sender}`.includes('@')
|
||||
? sender
|
||||
: `${sender}@gcm.googleapis.com`,
|
||||
type: 'remote',
|
||||
data: {},
|
||||
};
|
||||
|
@ -57,7 +59,6 @@ export default class RemoteMessage {
|
|||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param data
|
||||
|
@ -65,7 +66,9 @@ export default class RemoteMessage {
|
|||
*/
|
||||
setData(data: Object = {}) {
|
||||
if (!isObject(data)) {
|
||||
throw new Error(`RemoteMessage:setData expects an object as the first parameter but got type '${typeof data}'.`);
|
||||
throw new Error(
|
||||
`RemoteMessage:setData expects an object as the first parameter but got type '${typeof data}'.`
|
||||
);
|
||||
}
|
||||
|
||||
const props = Object.keys(data);
|
||||
|
|
|
@ -33,10 +33,7 @@ const WILL_PRESENT_RESULT = {
|
|||
None: 'UNNotificationPresentationOptionNone',
|
||||
};
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
EVENT_TYPE.RefreshToken,
|
||||
EVENT_TYPE.Notification,
|
||||
];
|
||||
const NATIVE_EVENTS = [EVENT_TYPE.RefreshToken, EVENT_TYPE.Notification];
|
||||
|
||||
const FirebaseMessaging = NativeModules.RNFirebaseMessaging;
|
||||
|
||||
|
@ -49,7 +46,6 @@ function finish(data) {
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!this._finishCalled && this._completionHandlerId) {
|
||||
let result = data;
|
||||
|
||||
|
@ -59,21 +55,35 @@ function finish(data) {
|
|||
case NOTIFICATION_TYPE.Remote:
|
||||
result = result || REMOTE_NOTIFICATION_RESULT.NoData;
|
||||
if (!Object.values(REMOTE_NOTIFICATION_RESULT).includes(result)) {
|
||||
throw new Error('Invalid REMOTE_NOTIFICATION_RESULT value, use messaging().REMOTE_NOTIFICATION_RESULT');
|
||||
throw new Error(
|
||||
'Invalid REMOTE_NOTIFICATION_RESULT value, use messaging().REMOTE_NOTIFICATION_RESULT'
|
||||
);
|
||||
}
|
||||
|
||||
FirebaseMessaging.finishRemoteNotification(this._completionHandlerId, result);
|
||||
FirebaseMessaging.finishRemoteNotification(
|
||||
this._completionHandlerId,
|
||||
result
|
||||
);
|
||||
return;
|
||||
case NOTIFICATION_TYPE.NotificationResponse:
|
||||
FirebaseMessaging.finishNotificationResponse(this._completionHandlerId);
|
||||
return;
|
||||
case NOTIFICATION_TYPE.WillPresent:
|
||||
result = result || (this.show_in_foreground ? WILL_PRESENT_RESULT.All : WILL_PRESENT_RESULT.None);
|
||||
result =
|
||||
result ||
|
||||
(this.show_in_foreground
|
||||
? WILL_PRESENT_RESULT.All
|
||||
: WILL_PRESENT_RESULT.None);
|
||||
if (!Object.values(WILL_PRESENT_RESULT).includes(result)) {
|
||||
throw new Error('Invalid WILL_PRESENT_RESULT value, use messaging().WILL_PRESENT_RESULT');
|
||||
throw new Error(
|
||||
'Invalid WILL_PRESENT_RESULT value, use messaging().WILL_PRESENT_RESULT'
|
||||
);
|
||||
}
|
||||
|
||||
FirebaseMessaging.finishWillPresentNotification(this._completionHandlerId, result);
|
||||
FirebaseMessaging.finishWillPresentNotification(
|
||||
this._completionHandlerId,
|
||||
result
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
@ -91,6 +101,7 @@ export default class Messaging extends ModuleBase {
|
|||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
@ -154,7 +165,10 @@ export default class Messaging extends ModuleBase {
|
|||
*/
|
||||
scheduleLocalNotification(notification: Object): Promise<void> {
|
||||
const _notification = Object.assign({}, notification);
|
||||
if (!notification.id) return Promise.reject(new Error('An id is required to schedule a local notification.'));
|
||||
if (!notification.id)
|
||||
return Promise.reject(
|
||||
new Error('An id is required to schedule a local notification.')
|
||||
);
|
||||
_notification.local_notification = true;
|
||||
return getNativeModule(this).scheduleLocalNotification(_notification);
|
||||
}
|
||||
|
@ -187,7 +201,8 @@ export default class Messaging extends ModuleBase {
|
|||
*/
|
||||
removeDeliveredNotification(id: string): Promise<void> {
|
||||
if (!id) return Promise.reject(new Error('Missing notification id'));
|
||||
if (id === '*') return getNativeModule(this).removeAllDeliveredNotifications();
|
||||
if (id === '*')
|
||||
return getNativeModule(this).removeAllDeliveredNotifications();
|
||||
return getNativeModule(this).removeDeliveredNotification(id);
|
||||
}
|
||||
|
||||
|
@ -200,7 +215,6 @@ export default class Messaging extends ModuleBase {
|
|||
return getNativeModule(this).requestPermissions();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set notification count badge number
|
||||
* @param n
|
||||
|
@ -222,10 +236,10 @@ export default class Messaging extends ModuleBase {
|
|||
* @param listener
|
||||
* @returns {*}
|
||||
*/
|
||||
onMessage(listener: (Object) => any): () => any {
|
||||
onMessage(listener: Object => any): () => any {
|
||||
const rnListener = SharedEventEmitter.addListener(
|
||||
EVENT_TYPE.Notification,
|
||||
async (event) => {
|
||||
async event => {
|
||||
const data = {
|
||||
...event,
|
||||
finish,
|
||||
|
@ -235,7 +249,7 @@ export default class Messaging extends ModuleBase {
|
|||
if (!data._finishCalled) {
|
||||
data.finish();
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
return () => rnListener.remove();
|
||||
}
|
||||
|
@ -245,8 +259,11 @@ export default class Messaging extends ModuleBase {
|
|||
* @param listener
|
||||
* @returns {*}
|
||||
*/
|
||||
onTokenRefresh(listener: (string) => any): () => any {
|
||||
const rnListener = SharedEventEmitter.addListener(EVENT_TYPE.RefreshToken, listener);
|
||||
onTokenRefresh(listener: string => any): () => any {
|
||||
const rnListener = SharedEventEmitter.addListener(
|
||||
EVENT_TYPE.RefreshToken,
|
||||
listener
|
||||
);
|
||||
return () => rnListener.remove();
|
||||
}
|
||||
|
||||
|
@ -272,7 +289,9 @@ export default class Messaging extends ModuleBase {
|
|||
*/
|
||||
send(remoteMessage: RemoteMessage): Promise<void> {
|
||||
if (!(remoteMessage instanceof RemoteMessage)) {
|
||||
throw new Error('messaging().send requires an instance of RemoteMessage as the first argument.');
|
||||
throw new Error(
|
||||
'messaging().send requires an instance of RemoteMessage as the first argument.'
|
||||
);
|
||||
}
|
||||
|
||||
return getNativeModule(this).send(remoteMessage.toJSON());
|
||||
|
|
|
@ -15,6 +15,7 @@ export default class PerformanceMonitoring extends ModuleBase {
|
|||
constructor(app: App) {
|
||||
super(app, {
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
|
|
@ -14,10 +14,7 @@ import type App from '../core/firebase-app';
|
|||
|
||||
const FirebaseStorage = NativeModules.RNFirebaseStorage;
|
||||
|
||||
const NATIVE_EVENTS = [
|
||||
'storage_event',
|
||||
'storage_error',
|
||||
];
|
||||
const NATIVE_EVENTS = ['storage_event', 'storage_error'];
|
||||
|
||||
export const MODULE_NAME = 'RNFirebaseStorage';
|
||||
export const NAMESPACE = 'storage';
|
||||
|
@ -32,17 +29,18 @@ export default class Storage extends ModuleBase {
|
|||
super(app, {
|
||||
events: NATIVE_EVENTS,
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: true,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'storage_event'),
|
||||
this._handleStorageEvent.bind(this),
|
||||
this._handleStorageEvent.bind(this)
|
||||
);
|
||||
|
||||
SharedEventEmitter.addListener(
|
||||
getAppEventName(this, 'storage_error'),
|
||||
this._handleStorageEvent.bind(this),
|
||||
this._handleStorageEvent.bind(this)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -117,12 +115,23 @@ export default class Storage extends ModuleBase {
|
|||
SharedEventEmitter.emit(this._getSubEventName(path, eventName), body);
|
||||
}
|
||||
|
||||
_addListener(path: string, eventName: string, cb: (evt: Object) => Object): void {
|
||||
_addListener(
|
||||
path: string,
|
||||
eventName: string,
|
||||
cb: (evt: Object) => Object
|
||||
): void {
|
||||
SharedEventEmitter.addListener(this._getSubEventName(path, eventName), cb);
|
||||
}
|
||||
|
||||
_removeListener(path: string, eventName: string, origCB: (evt: Object) => Object): void {
|
||||
SharedEventEmitter.removeListener(this._getSubEventName(path, eventName), origCB);
|
||||
_removeListener(
|
||||
path: string,
|
||||
eventName: string,
|
||||
origCB: (evt: Object) => Object
|
||||
): void {
|
||||
SharedEventEmitter.removeListener(
|
||||
this._getSubEventName(path, eventName),
|
||||
origCB
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -137,15 +146,18 @@ export const statics = {
|
|||
CANCELLED: 'cancelled',
|
||||
ERROR: 'error',
|
||||
},
|
||||
Native: FirebaseStorage ? {
|
||||
Native: FirebaseStorage
|
||||
? {
|
||||
MAIN_BUNDLE_PATH: FirebaseStorage.MAIN_BUNDLE_PATH,
|
||||
CACHES_DIRECTORY_PATH: FirebaseStorage.CACHES_DIRECTORY_PATH,
|
||||
DOCUMENT_DIRECTORY_PATH: FirebaseStorage.DOCUMENT_DIRECTORY_PATH,
|
||||
EXTERNAL_DIRECTORY_PATH: FirebaseStorage.EXTERNAL_DIRECTORY_PATH,
|
||||
EXTERNAL_STORAGE_DIRECTORY_PATH: FirebaseStorage.EXTERNAL_STORAGE_DIRECTORY_PATH,
|
||||
EXTERNAL_STORAGE_DIRECTORY_PATH:
|
||||
FirebaseStorage.EXTERNAL_STORAGE_DIRECTORY_PATH,
|
||||
TEMP_DIRECTORY_PATH: FirebaseStorage.TEMP_DIRECTORY_PATH,
|
||||
LIBRARY_DIRECTORY_PATH: FirebaseStorage.LIBRARY_DIRECTORY_PATH,
|
||||
FILETYPE_REGULAR: FirebaseStorage.FILETYPE_REGULAR,
|
||||
FILETYPE_DIRECTORY: FirebaseStorage.FILETYPE_DIRECTORY,
|
||||
} : {},
|
||||
}
|
||||
: {},
|
||||
};
|
||||
|
|
|
@ -7,7 +7,6 @@ import StorageTask, { UPLOAD_TASK, DOWNLOAD_TASK } from './task';
|
|||
import { getNativeModule } from '../../utils/native';
|
||||
import type Storage from './';
|
||||
|
||||
|
||||
/**
|
||||
* @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference
|
||||
*/
|
||||
|
@ -75,7 +74,11 @@ export default class StorageReference extends ReferenceBase {
|
|||
* @return {Promise}
|
||||
*/
|
||||
downloadFile(filePath: string): Promise<Object> {
|
||||
return new StorageTask(DOWNLOAD_TASK, getNativeModule(this._storage).downloadFile(this.path, filePath), this);
|
||||
return new StorageTask(
|
||||
DOWNLOAD_TASK,
|
||||
getNativeModule(this._storage).downloadFile(this.path, filePath),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -94,6 +97,10 @@ export default class StorageReference extends ReferenceBase {
|
|||
*/
|
||||
putFile(filePath: Object, metadata: Object = {}): Promise<Object> {
|
||||
const _filePath = filePath.replace('file://', '');
|
||||
return new StorageTask(UPLOAD_TASK, getNativeModule(this._storage).putFile(this.path, _filePath, metadata), this);
|
||||
return new StorageTask(
|
||||
UPLOAD_TASK,
|
||||
getNativeModule(this._storage).putFile(this.path, _filePath, metadata),
|
||||
this
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,31 +12,33 @@ export const DOWNLOAD_TASK = 'download';
|
|||
|
||||
declare type UploadTaskSnapshotType = {
|
||||
bytesTransferred: number,
|
||||
downloadURL: string|null,
|
||||
downloadURL: string | null,
|
||||
metadata: Object, // TODO flow type def for https://firebase.google.com/docs/reference/js/firebase.storage.FullMetadata.html
|
||||
ref: StorageReference,
|
||||
state: (
|
||||
typeof StorageStatics.TaskState.RUNNING
|
||||
state:
|
||||
| typeof StorageStatics.TaskState.RUNNING
|
||||
| typeof StorageStatics.TaskState.PAUSED
|
||||
| typeof StorageStatics.TaskState.SUCCESS
|
||||
| typeof StorageStatics.TaskState.CANCELLED
|
||||
| typeof StorageStatics.TaskState.ERROR
|
||||
),
|
||||
| typeof StorageStatics.TaskState.ERROR,
|
||||
task: StorageTask,
|
||||
totalBytes: number,
|
||||
};
|
||||
|
||||
declare type FuncSnapshotType = null|(snapshot: UploadTaskSnapshotType) => any;
|
||||
declare type FuncSnapshotType =
|
||||
| null
|
||||
| ((snapshot: UploadTaskSnapshotType) => any);
|
||||
|
||||
declare type FuncErrorType = null|(error: Error) => any;
|
||||
declare type FuncErrorType = null | ((error: Error) => any);
|
||||
|
||||
declare type NextOrObserverType = null |
|
||||
{
|
||||
declare type NextOrObserverType =
|
||||
| null
|
||||
| {
|
||||
next?: FuncSnapshotType,
|
||||
error?: FuncErrorType,
|
||||
complete?:FuncSnapshotType
|
||||
} |
|
||||
FuncSnapshotType;
|
||||
complete?: FuncSnapshotType,
|
||||
}
|
||||
| FuncSnapshotType;
|
||||
|
||||
/**
|
||||
* @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask
|
||||
|
@ -49,7 +51,11 @@ export default class StorageTask {
|
|||
then: () => Promise<*>;
|
||||
catch: () => Promise<*>;
|
||||
|
||||
constructor(type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK, promise: Promise<*>, storageRef: StorageReference) {
|
||||
constructor(
|
||||
type: typeof UPLOAD_TASK | typeof DOWNLOAD_TASK,
|
||||
promise: Promise<*>,
|
||||
storageRef: StorageReference
|
||||
) {
|
||||
this.type = type;
|
||||
this.ref = storageRef;
|
||||
this.storage = storageRef._storage;
|
||||
|
@ -66,9 +72,9 @@ export default class StorageTask {
|
|||
* @returns {Promise.<T>}
|
||||
* @private
|
||||
*/
|
||||
_interceptSnapshotEvent(f: ?Function): null | () => * {
|
||||
_interceptSnapshotEvent(f: ?Function): null | (() => *) {
|
||||
if (!isFunction(f)) return null;
|
||||
return (snapshot) => {
|
||||
return snapshot => {
|
||||
const _snapshot = Object.assign({}, snapshot);
|
||||
_snapshot.task = this;
|
||||
_snapshot.ref = this.ref;
|
||||
|
@ -82,9 +88,9 @@ export default class StorageTask {
|
|||
* @returns {*}
|
||||
* @private
|
||||
*/
|
||||
_interceptErrorEvent(f: ?Function): null | (Error) => * {
|
||||
_interceptErrorEvent(f: ?Function): null | (Error => *) {
|
||||
if (!isFunction(f)) return null;
|
||||
return (error) => {
|
||||
return error => {
|
||||
const _error = new Error(error.message);
|
||||
// $FlowFixMe
|
||||
_error.code = error.code;
|
||||
|
@ -100,7 +106,11 @@ export default class StorageTask {
|
|||
* @returns {function()}
|
||||
* @private
|
||||
*/
|
||||
_subscribe(nextOrObserver: NextOrObserverType, error: FuncErrorType, complete: FuncSnapshotType): Function {
|
||||
_subscribe(
|
||||
nextOrObserver: NextOrObserverType,
|
||||
error: FuncErrorType,
|
||||
complete: FuncSnapshotType
|
||||
): Function {
|
||||
let _error;
|
||||
let _next;
|
||||
let _complete;
|
||||
|
@ -119,28 +129,31 @@ export default class StorageTask {
|
|||
this.storage._addListener(
|
||||
this.path,
|
||||
StorageStatics.TaskEvent.STATE_CHANGED,
|
||||
_next,
|
||||
_next
|
||||
);
|
||||
}
|
||||
if (_error) {
|
||||
this.storage._addListener(
|
||||
this.path,
|
||||
`${this.type}_failure`,
|
||||
_error,
|
||||
);
|
||||
this.storage._addListener(this.path, `${this.type}_failure`, _error);
|
||||
}
|
||||
if (_complete) {
|
||||
this.storage._addListener(
|
||||
this.path,
|
||||
`${this.type}_success`,
|
||||
_complete,
|
||||
);
|
||||
this.storage._addListener(this.path, `${this.type}_success`, _complete);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (_next) this.storage._removeListener(this.path, StorageStatics.TaskEvent.STATE_CHANGED, _next);
|
||||
if (_error) this.storage._removeListener(this.path, `${this.type}_failure`, _error);
|
||||
if (_complete) this.storage._removeListener(this.path, `${this.type}_success`, _complete);
|
||||
if (_next)
|
||||
this.storage._removeListener(
|
||||
this.path,
|
||||
StorageStatics.TaskEvent.STATE_CHANGED,
|
||||
_next
|
||||
);
|
||||
if (_error)
|
||||
this.storage._removeListener(this.path, `${this.type}_failure`, _error);
|
||||
if (_complete)
|
||||
this.storage._removeListener(
|
||||
this.path,
|
||||
`${this.type}_success`,
|
||||
_complete
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -152,13 +165,24 @@ export default class StorageTask {
|
|||
* @param complete
|
||||
* @returns {function()}
|
||||
*/
|
||||
on(event: string = StorageStatics.TaskEvent.STATE_CHANGED, nextOrObserver: NextOrObserverType, error: FuncErrorType, complete: FuncSnapshotType): Function {
|
||||
on(
|
||||
event: string = StorageStatics.TaskEvent.STATE_CHANGED,
|
||||
nextOrObserver: NextOrObserverType,
|
||||
error: FuncErrorType,
|
||||
complete: FuncSnapshotType
|
||||
): Function {
|
||||
if (!event) {
|
||||
throw new Error('StorageTask.on listener is missing required string argument \'event\'.');
|
||||
throw new Error(
|
||||
"StorageTask.on listener is missing required string argument 'event'."
|
||||
);
|
||||
}
|
||||
|
||||
if (event !== StorageStatics.TaskEvent.STATE_CHANGED) {
|
||||
throw new Error(`StorageTask.on event argument must be a string with a value of '${StorageStatics.TaskEvent.STATE_CHANGED}'`);
|
||||
throw new Error(
|
||||
`StorageTask.on event argument must be a string with a value of '${
|
||||
StorageStatics.TaskEvent.STATE_CHANGED
|
||||
}'`
|
||||
);
|
||||
}
|
||||
|
||||
// if only event provided return the subscriber function
|
||||
|
@ -170,16 +194,22 @@ export default class StorageTask {
|
|||
}
|
||||
|
||||
pause() {
|
||||
throw new Error('.pause() is not currently supported by react-native-firebase');
|
||||
throw new Error(
|
||||
'.pause() is not currently supported by react-native-firebase'
|
||||
);
|
||||
}
|
||||
|
||||
resume() {
|
||||
// todo
|
||||
throw new Error('.resume() is not currently supported by react-native-firebase');
|
||||
throw new Error(
|
||||
'.resume() is not currently supported by react-native-firebase'
|
||||
);
|
||||
}
|
||||
|
||||
cancel() {
|
||||
// todo
|
||||
throw new Error('.cancel() is not currently supported by react-native-firebase');
|
||||
throw new Error(
|
||||
'.cancel() is not currently supported by react-native-firebase'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
// @flow
|
||||
import { NativeModules } from 'react-native';
|
||||
// import { version as ReactVersion } from 'react';
|
||||
// import ReactNativeVersion from 'react-native/Libraries/Core/ReactNativeVersion';
|
||||
import INTERNALS from '../../utils/internals';
|
||||
import { isIOS } from '../../utils';
|
||||
import ModuleBase from '../../utils/ModuleBase';
|
||||
import PACKAGE from '../../../package.json';
|
||||
import type App from '../core/firebase-app';
|
||||
|
||||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
|
@ -14,13 +12,21 @@ type GoogleApiAvailabilityType = {
|
|||
isAvailable: boolean,
|
||||
isUserResolvableError?: boolean,
|
||||
hasResolution?: boolean,
|
||||
error?: string
|
||||
}
|
||||
error?: string,
|
||||
};
|
||||
|
||||
export const MODULE_NAME = 'RNFirebaseUtils';
|
||||
export const NAMESPACE = 'utils';
|
||||
|
||||
export default class RNFirebaseUtils extends ModuleBase {
|
||||
constructor(app: App) {
|
||||
super(app, {
|
||||
moduleName: MODULE_NAME,
|
||||
multiApp: false,
|
||||
namespace: NAMESPACE,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -30,12 +36,16 @@ export default class RNFirebaseUtils extends ModuleBase {
|
|||
const { status } = this.playServicesAvailability;
|
||||
|
||||
if (!this.playServicesAvailability.isAvailable) {
|
||||
if (INTERNALS.OPTIONS.promptOnMissingPlayServices && this.playServicesAvailability.isUserResolvableError) {
|
||||
if (
|
||||
INTERNALS.OPTIONS.promptOnMissingPlayServices &&
|
||||
this.playServicesAvailability.isUserResolvableError
|
||||
) {
|
||||
this.promptForPlayServices();
|
||||
} else {
|
||||
const error = INTERNALS.STRINGS.ERROR_PLAY_SERVICES(status);
|
||||
if (INTERNALS.OPTIONS.errorOnMissingPlayServices) {
|
||||
if (status === 2) console.warn(error); // only warn if it exists but may need an update
|
||||
if (status === 2)
|
||||
console.warn(error); // only warn if it exists but may need an update
|
||||
else throw new Error(error);
|
||||
} else {
|
||||
console.warn(error);
|
||||
|
@ -74,7 +84,12 @@ export default class RNFirebaseUtils extends ModuleBase {
|
|||
* @return {RNFirebase.GoogleApiAvailabilityType|{isAvailable: boolean, status: number}}
|
||||
*/
|
||||
get playServicesAvailability(): GoogleApiAvailabilityType {
|
||||
return FirebaseCoreModule.playServicesAvailability || { isAvailable: true, status: 0 };
|
||||
return (
|
||||
FirebaseCoreModule.playServicesAvailability || {
|
||||
isAvailable: true,
|
||||
status: 0,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -96,11 +111,4 @@ export default class RNFirebaseUtils extends ModuleBase {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
export const statics = {
|
||||
// VERSIONS: {
|
||||
// react: ReactVersion,
|
||||
// 'react-native': Object.values(ReactNativeVersion.version).slice(0, 3).join('.'),
|
||||
// 'react-native-firebase': PACKAGE.version,
|
||||
// },
|
||||
};
|
||||
export const statics = {};
|
||||
|
|
|
@ -35,24 +35,46 @@ export type FirebaseError = {
|
|||
stack: string,
|
||||
path: string,
|
||||
details: string,
|
||||
modifiers: string
|
||||
}
|
||||
modifiers: string,
|
||||
};
|
||||
|
||||
export type FirebaseModule = $Subtype<ModuleBase>;
|
||||
|
||||
export type FirebaseModuleConfig = {
|
||||
events?: string[],
|
||||
moduleName: FirebaseModuleName,
|
||||
multiApp: boolean,
|
||||
namespace: FirebaseNamespace,
|
||||
}
|
||||
};
|
||||
|
||||
export type FirebaseModuleName = 'RNFirebaseAdmob' | 'RNFirebaseAnalytics' | 'RNFirebaseAuth'
|
||||
| 'RNFirebaseRemoteConfig' | 'RNFirebaseCrash' | 'RNFirebaseCrashlytics' | 'RNFirebaseDatabase'
|
||||
| 'RNFirebaseFirestore' | 'RNFirebaseLinks' | 'RNFirebaseMessaging' | 'RNFirebasePerformance'
|
||||
| 'RNFirebaseStorage' | 'RNFirebaseUtils';
|
||||
export type FirebaseModuleName =
|
||||
| 'RNFirebaseAdMob'
|
||||
| 'RNFirebaseAnalytics'
|
||||
| 'RNFirebaseAuth'
|
||||
| 'RNFirebaseRemoteConfig'
|
||||
| 'RNFirebaseCrash'
|
||||
| 'RNFirebaseCrashlytics'
|
||||
| 'RNFirebaseDatabase'
|
||||
| 'RNFirebaseFirestore'
|
||||
| 'RNFirebaseLinks'
|
||||
| 'RNFirebaseMessaging'
|
||||
| 'RNFirebasePerformance'
|
||||
| 'RNFirebaseStorage'
|
||||
| 'RNFirebaseUtils';
|
||||
|
||||
export type FirebaseNamespace = 'admob' | 'analytics' | 'auth' | 'config' | 'crash'
|
||||
| 'crashlytics' | 'database' | 'firestore' | 'links' | 'messaging' | 'perf' | 'storage'
|
||||
export type FirebaseNamespace =
|
||||
| 'admob'
|
||||
| 'analytics'
|
||||
| 'auth'
|
||||
| 'config'
|
||||
| 'crash'
|
||||
| 'crashlytics'
|
||||
| 'database'
|
||||
| 'firestore'
|
||||
| 'links'
|
||||
| 'messaging'
|
||||
| 'perf'
|
||||
| 'storage'
|
||||
| 'utils';
|
||||
|
||||
export type FirebaseOptions = {
|
||||
|
@ -62,7 +84,7 @@ export type FirebaseOptions = {
|
|||
messagingSenderId: string,
|
||||
projectId: string,
|
||||
storageBucket: string,
|
||||
}
|
||||
};
|
||||
|
||||
export type FirebaseModuleAndStatics<M: FirebaseModule, S: FirebaseStatics> = {
|
||||
(): M,
|
||||
|
@ -92,12 +114,6 @@ export type ConfigModule = {
|
|||
nativeModuleExists: boolean,
|
||||
} & ConfigStatics;
|
||||
|
||||
export type AuthCredential = {
|
||||
providerId: string,
|
||||
token: string,
|
||||
secret: string
|
||||
}
|
||||
|
||||
/* Auth types */
|
||||
|
||||
export type AuthModule = {
|
||||
|
@ -105,19 +121,6 @@ export type AuthModule = {
|
|||
nativeModuleExists: boolean,
|
||||
} & AuthStatics;
|
||||
|
||||
export type ActionCodeSettings = {
|
||||
android: {
|
||||
installApp?: boolean,
|
||||
minimumVersion?: string,
|
||||
packageName: string,
|
||||
},
|
||||
handleCodeInApp?: boolean,
|
||||
iOS: {
|
||||
bundleId?: string,
|
||||
},
|
||||
url: string,
|
||||
}
|
||||
|
||||
/* Crash types */
|
||||
|
||||
export type CrashModule = {
|
||||
|
@ -133,14 +136,14 @@ export type DatabaseModule = {
|
|||
} & DatabaseStatics;
|
||||
|
||||
export type DatabaseModifier = {
|
||||
id: string;
|
||||
type: 'orderBy' | 'limit' | 'filter';
|
||||
name?: string;
|
||||
key?: string;
|
||||
limit?: number;
|
||||
value?: any;
|
||||
valueType?: string;
|
||||
}
|
||||
id: string,
|
||||
type: 'orderBy' | 'limit' | 'filter',
|
||||
name?: string,
|
||||
key?: string,
|
||||
limit?: number,
|
||||
value?: any,
|
||||
valueType?: string,
|
||||
};
|
||||
|
||||
/* Fabric types */
|
||||
export type CrashlyticsModule = {
|
||||
|
@ -150,7 +153,7 @@ export type CrashlyticsModule = {
|
|||
|
||||
export type FabricModule = {
|
||||
crashlytics: CrashlyticsModule,
|
||||
}
|
||||
};
|
||||
|
||||
/* Firestore types */
|
||||
|
||||
|
@ -164,30 +167,41 @@ export type FirestoreNativeDocumentChange = {
|
|||
newIndex: number,
|
||||
oldIndex: number,
|
||||
type: string,
|
||||
}
|
||||
};
|
||||
|
||||
export type FirestoreNativeDocumentSnapshot = {
|
||||
data: { [string]: FirestoreTypeMap },
|
||||
metadata: FirestoreSnapshotMetadata,
|
||||
path: string,
|
||||
}
|
||||
};
|
||||
|
||||
export type FirestoreSnapshotMetadata = {
|
||||
fromCache: boolean,
|
||||
hasPendingWrites: boolean,
|
||||
}
|
||||
};
|
||||
|
||||
export type FirestoreQueryDirection = 'DESC' | 'desc' | 'ASC' | 'asc';
|
||||
export type FirestoreQueryOperator = '<' | '<=' | '=' | '==' | '>' | '>=';
|
||||
|
||||
export type FirestoreTypeMap = {
|
||||
type: 'array' | 'boolean' | 'date' | 'fieldvalue' | 'geopoint' | 'null' | 'number' | 'object' | 'reference' | 'string',
|
||||
type:
|
||||
| 'array'
|
||||
| 'boolean'
|
||||
| 'date'
|
||||
| 'documentid'
|
||||
| 'fieldvalue'
|
||||
| 'geopoint'
|
||||
| 'null'
|
||||
| 'number'
|
||||
| 'object'
|
||||
| 'reference'
|
||||
| 'string',
|
||||
value: any,
|
||||
}
|
||||
};
|
||||
|
||||
export type FirestoreWriteOptions = {
|
||||
merge?: boolean,
|
||||
}
|
||||
};
|
||||
|
||||
/* Links types */
|
||||
|
||||
|
|
|
@ -29,7 +29,10 @@ export default class ModuleBase {
|
|||
|
||||
// check if native module exists as all native
|
||||
initialiseNativeModule(this, config);
|
||||
initialiseLogger(this, `${app.name}:${moduleName.replace('RNFirebase', '')}`);
|
||||
initialiseLogger(
|
||||
this,
|
||||
`${app.name}:${moduleName.replace('RNFirebase', '')}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,14 @@ export default class ReferenceBase {
|
|||
path: string;
|
||||
|
||||
constructor(path: string) {
|
||||
this.path = path || '/';
|
||||
if (path) {
|
||||
this.path =
|
||||
path.length > 1 && path.endsWith('/')
|
||||
? path.substring(0, path.length - 1)
|
||||
: path;
|
||||
} else {
|
||||
this.path = '/';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -15,6 +22,8 @@ export default class ReferenceBase {
|
|||
* {@link https://firebase.google.com/docs/reference/js/firebase.database.Reference#key}
|
||||
*/
|
||||
get key(): string | null {
|
||||
return this.path === '/' ? null : this.path.substring(this.path.lastIndexOf('/') + 1);
|
||||
return this.path === '/'
|
||||
? null
|
||||
: this.path.substring(this.path.lastIndexOf('/') + 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ import DatabaseSnapshot from '../modules/database/snapshot';
|
|||
import DatabaseReference from '../modules/database/reference';
|
||||
import { isString, nativeToJSError } from '../utils';
|
||||
|
||||
type Listener = (DatabaseSnapshot) => any;
|
||||
type Listener = DatabaseSnapshot => any;
|
||||
|
||||
type Registration = {
|
||||
key: string,
|
||||
|
@ -19,7 +19,7 @@ type Registration = {
|
|||
listener: Listener,
|
||||
eventRegistrationKey: string,
|
||||
ref: DatabaseReference,
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Internally used to manage firebase database realtime event
|
||||
|
@ -28,16 +28,18 @@ type Registration = {
|
|||
class SyncTree {
|
||||
_nativeEmitter: NativeEventEmitter;
|
||||
_reverseLookup: { [string]: Registration };
|
||||
_tree: { [string]: { [string]: { [string]: Listener }}};
|
||||
_tree: { [string]: { [string]: { [string]: Listener } } };
|
||||
|
||||
constructor() {
|
||||
this._tree = {};
|
||||
this._reverseLookup = {};
|
||||
if (NativeModules.RNFirebaseDatabase) {
|
||||
this._nativeEmitter = new NativeEventEmitter(NativeModules.RNFirebaseDatabase);
|
||||
this._nativeEmitter = new NativeEventEmitter(
|
||||
NativeModules.RNFirebaseDatabase
|
||||
);
|
||||
this._nativeEmitter.addListener(
|
||||
'database_sync_event',
|
||||
this._handleSyncEvent.bind(this),
|
||||
this._handleSyncEvent.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -82,11 +84,10 @@ class SyncTree {
|
|||
return SharedEventEmitter.emit(
|
||||
eventRegistrationKey,
|
||||
new DatabaseSnapshot(registration.ref, snapshot),
|
||||
previousChildName,
|
||||
previousChildName
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Routes native database query listener cancellation events to their js counterparts.
|
||||
*
|
||||
|
@ -96,7 +97,10 @@ class SyncTree {
|
|||
_handleErrorEvent(event) {
|
||||
// console.log('SyncTree.ERROR >>>', event);
|
||||
const { code, message } = event.error;
|
||||
const { eventRegistrationKey, registrationCancellationKey } = event.registration;
|
||||
const {
|
||||
eventRegistrationKey,
|
||||
registrationCancellationKey,
|
||||
} = event.registration;
|
||||
|
||||
const registration = this.getRegistration(registrationCancellationKey);
|
||||
|
||||
|
@ -121,7 +125,9 @@ class SyncTree {
|
|||
* @return {null}
|
||||
*/
|
||||
getRegistration(registration: string): Registration | null {
|
||||
return this._reverseLookup[registration] ? Object.assign({}, this._reverseLookup[registration]) : null;
|
||||
return this._reverseLookup[registration]
|
||||
? Object.assign({}, this._reverseLookup[registration])
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,7 +165,9 @@ class SyncTree {
|
|||
|
||||
for (let i = 0, len = registrations.length; i < len; i++) {
|
||||
const registration = registrations[i];
|
||||
const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(registration);
|
||||
const subscriptions = SharedEventEmitter._subscriber.getSubscriptionsForType(
|
||||
registration
|
||||
);
|
||||
if (subscriptions) {
|
||||
for (let j = 0, l = subscriptions.length; j < l; j++) {
|
||||
const subscription = subscriptions[j];
|
||||
|
@ -188,7 +196,10 @@ class SyncTree {
|
|||
const eventKeys = Object.keys(this._tree[path] || {});
|
||||
|
||||
for (let i = 0, len = eventKeys.length; i < len; i++) {
|
||||
Array.prototype.push.apply(out, Object.keys(this._tree[path][eventKeys[i]]));
|
||||
Array.prototype.push.apply(
|
||||
out,
|
||||
Object.keys(this._tree[path][eventKeys[i]])
|
||||
);
|
||||
}
|
||||
|
||||
return out;
|
||||
|
@ -216,11 +227,17 @@ class SyncTree {
|
|||
* @param listener
|
||||
* @return {Array}
|
||||
*/
|
||||
getOneByPathEventListener(path: string, eventType: string, listener: Function): ?string {
|
||||
getOneByPathEventListener(
|
||||
path: string,
|
||||
eventType: string,
|
||||
listener: Function
|
||||
): ?string {
|
||||
if (!this._tree[path]) return null;
|
||||
if (!this._tree[path][eventType]) return null;
|
||||
|
||||
const registrationsForPathEvent = Object.entries(this._tree[path][eventType]);
|
||||
const registrationsForPathEvent = Object.entries(
|
||||
this._tree[path][eventType]
|
||||
);
|
||||
|
||||
for (let i = 0; i < registrationsForPathEvent.length; i++) {
|
||||
const registration = registrationsForPathEvent[i];
|
||||
|
@ -230,7 +247,6 @@ class SyncTree {
|
|||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register a new listener.
|
||||
*
|
||||
|
@ -256,7 +272,7 @@ class SyncTree {
|
|||
if (once) {
|
||||
SharedEventEmitter.once(
|
||||
eventRegistrationKey,
|
||||
this._onOnceRemoveRegistration(eventRegistrationKey, listener),
|
||||
this._onOnceRemoveRegistration(eventRegistrationKey, listener)
|
||||
);
|
||||
} else {
|
||||
SharedEventEmitter.addListener(eventRegistrationKey, listener);
|
||||
|
|
|
@ -18,7 +18,7 @@ import type {
|
|||
const FirebaseCoreModule = NativeModules.RNFirebase;
|
||||
|
||||
const APPS: { [string]: App } = {};
|
||||
const APP_MODULES: { [App]: { [string]: FirebaseModule }} = {};
|
||||
const APP_MODULES: { [App]: { [string]: FirebaseModule } } = {};
|
||||
const DEFAULT_APP_NAME = '[DEFAULT]';
|
||||
|
||||
export default {
|
||||
|
@ -43,15 +43,23 @@ export default {
|
|||
* @return {function()}
|
||||
* @private
|
||||
*/
|
||||
appModule<M: FirebaseModule>(app: App, namespace: FirebaseNamespace, InstanceClass: Class<M>): () => FirebaseModule {
|
||||
appModule<M: FirebaseModule>(
|
||||
app: App,
|
||||
namespace: FirebaseNamespace,
|
||||
InstanceClass: Class<M>
|
||||
): () => FirebaseModule {
|
||||
return (): M => {
|
||||
if (!APP_MODULES[app]) {
|
||||
APP_MODULES[app] = {};
|
||||
}
|
||||
|
||||
if (isAndroid && namespace !== 'utils' && !INTERNALS.FLAGS.checkedPlayServices) {
|
||||
if (
|
||||
isAndroid &&
|
||||
namespace !== 'utils' &&
|
||||
!INTERNALS.FLAGS.checkedPlayServices
|
||||
) {
|
||||
INTERNALS.FLAGS.checkedPlayServices = true;
|
||||
this.utils().checkPlayServicesAvailability();
|
||||
app.utils().checkPlayServicesAvailability();
|
||||
}
|
||||
|
||||
if (!APP_MODULES[app][namespace]) {
|
||||
|
@ -148,16 +156,21 @@ export default {
|
|||
* @param InstanceClass
|
||||
* @return {function(App=)}
|
||||
*/
|
||||
moduleAndStatics<M: FirebaseModule, S: FirebaseStatics>(namespace: FirebaseNamespace, statics: S, moduleName: FirebaseModuleName): FirebaseModuleAndStatics<M, S> {
|
||||
moduleAndStatics<M: FirebaseModule, S: FirebaseStatics>(
|
||||
namespace: FirebaseNamespace,
|
||||
statics: S,
|
||||
moduleName: FirebaseModuleName
|
||||
): FirebaseModuleAndStatics<M, S> {
|
||||
const getModule = (app?: App): FirebaseModule => {
|
||||
let _app = app;
|
||||
|
||||
// throw an error if it's not a valid app instance
|
||||
if (_app && !(_app instanceof App)) throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
|
||||
|
||||
if (_app && !(_app instanceof App))
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_NOT_APP(namespace));
|
||||
else if (!_app)
|
||||
// default to the 'DEFAULT' app if no arg provided - will throw an error
|
||||
// if default app not initialized
|
||||
else if (!_app) _app = this.app(DEFAULT_APP_NAME);
|
||||
_app = this.app(DEFAULT_APP_NAME);
|
||||
if (namespace === 'crashlytics') {
|
||||
return _app.fabric[namespace]();
|
||||
}
|
||||
|
|
|
@ -12,11 +12,15 @@ const NATIVE_SUBSCRIPTIONS: { [string]: boolean } = {};
|
|||
|
||||
export const SharedEventEmitter = new EventEmitter();
|
||||
|
||||
export const getAppEventName = (module: ModuleBase, eventName: string): string => {
|
||||
return `${module.app.name}-${eventName}`;
|
||||
};
|
||||
export const getAppEventName = (
|
||||
module: ModuleBase,
|
||||
eventName: string
|
||||
): string => `${module.app.name}-${eventName}`;
|
||||
|
||||
const getNativeEmitter = (moduleName: FirebaseModuleName, module: ModuleBase): NativeEventEmitter => {
|
||||
const getNativeEmitter = (
|
||||
moduleName: FirebaseModuleName,
|
||||
module: ModuleBase
|
||||
): NativeEventEmitter => {
|
||||
const name = `${module.app.name}-${moduleName}`;
|
||||
const nativeModule = NativeModules[moduleName];
|
||||
if (!NATIVE_EMITTERS[name]) {
|
||||
|
@ -35,10 +39,14 @@ const getNativeEmitter = (moduleName: FirebaseModuleName, module: ModuleBase): N
|
|||
* @param eventName
|
||||
* @private
|
||||
*/
|
||||
const subscribeToNativeModuleEvents = (moduleName: FirebaseModuleName, module: ModuleBase, eventName: string): void => {
|
||||
const subscribeToNativeModuleEvents = (
|
||||
moduleName: FirebaseModuleName,
|
||||
module: ModuleBase,
|
||||
eventName: string
|
||||
): void => {
|
||||
if (!NATIVE_SUBSCRIPTIONS[eventName]) {
|
||||
const nativeEmitter = getNativeEmitter(moduleName, module);
|
||||
nativeEmitter.addListener(eventName, (event) => {
|
||||
nativeEmitter.addListener(eventName, event => {
|
||||
if (event.appName) {
|
||||
// native event has an appName property - auto prefix and internally emit
|
||||
SharedEventEmitter.emit(`${event.appName}-${eventName}`, event);
|
||||
|
@ -52,7 +60,10 @@ const subscribeToNativeModuleEvents = (moduleName: FirebaseModuleName, module: M
|
|||
}
|
||||
};
|
||||
|
||||
export const initialiseNativeModuleEventEmitter = (module: ModuleBase, config: FirebaseModuleConfig): void => {
|
||||
export const initialiseNativeModuleEventEmitter = (
|
||||
module: ModuleBase,
|
||||
config: FirebaseModuleConfig
|
||||
): void => {
|
||||
const { events, moduleName } = config;
|
||||
if (events && events.length) {
|
||||
for (let i = 0, len = events.length; i < len; i++) {
|
||||
|
|
|
@ -4,8 +4,10 @@ import { Platform } from 'react-native';
|
|||
// todo cleanup unused utilities from legacy code
|
||||
|
||||
// modeled after base64 web-safe chars, but ordered by ASCII
|
||||
const PUSH_CHARS = '-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
|
||||
const AUTO_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const PUSH_CHARS =
|
||||
'-0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz';
|
||||
const AUTO_ID_CHARS =
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
const { hasOwnProperty } = Object;
|
||||
|
||||
// const DEFAULT_CHUNK_SIZE = 50;
|
||||
|
@ -18,7 +20,11 @@ const { hasOwnProperty } = Object;
|
|||
* @param joiner
|
||||
* @returns {*}
|
||||
*/
|
||||
export function deepGet(object: Object, path: string, joiner?: string = '/'): any {
|
||||
export function deepGet(
|
||||
object: Object,
|
||||
path: string,
|
||||
joiner?: string = '/'
|
||||
): any {
|
||||
const keys = path.split(joiner);
|
||||
|
||||
let i = 0;
|
||||
|
@ -42,7 +48,11 @@ export function deepGet(object: Object, path: string, joiner?: string = '/'): an
|
|||
* @param joiner
|
||||
* @returns {*}
|
||||
*/
|
||||
export function deepExists(object: Object, path: string, joiner?: string = '/'): boolean {
|
||||
export function deepExists(
|
||||
object: Object,
|
||||
path: string,
|
||||
joiner?: string = '/'
|
||||
): boolean {
|
||||
const keys = path.split(joiner);
|
||||
|
||||
let i = 0;
|
||||
|
@ -64,18 +74,23 @@ export function deepExists(object: Object, path: string, joiner?: string = '/'):
|
|||
* @param obj2
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function areObjectKeysContainedInOther(obj1 : Object, obj2: Object): boolean {
|
||||
export function areObjectKeysContainedInOther(
|
||||
obj1: Object,
|
||||
obj2: Object
|
||||
): boolean {
|
||||
if (!isObject(obj1) || !isObject(obj2)) {
|
||||
return false;
|
||||
}
|
||||
const keys1 = Object.keys(obj1);
|
||||
const keys2 = Object.keys(obj2);
|
||||
if (isArrayContainedInOther(keys1, keys2)) {
|
||||
return keys1.filter((key) => {
|
||||
return isObject(obj1[key]);
|
||||
}).reduce((acc, cur) => {
|
||||
return acc && areObjectKeysContainedInOther(obj1[cur], obj2[cur]);
|
||||
}, true);
|
||||
return keys1
|
||||
.filter(key => isObject(obj1[key]))
|
||||
.reduce(
|
||||
(acc, cur) =>
|
||||
acc && areObjectKeysContainedInOther(obj1[cur], obj2[cur]),
|
||||
true
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
@ -86,13 +101,14 @@ export function areObjectKeysContainedInOther(obj1 : Object, obj2: Object): bool
|
|||
* @param arr2
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isArrayContainedInOther(arr1: Array<*>, arr2: Array<*>): boolean {
|
||||
export function isArrayContainedInOther(
|
||||
arr1: Array<*>,
|
||||
arr2: Array<*>
|
||||
): boolean {
|
||||
if (!Array.isArray(arr1) || !Array.isArray(arr2)) {
|
||||
return false;
|
||||
}
|
||||
return arr1.reduce((acc, cur) => {
|
||||
return acc && arr2.includes(cur);
|
||||
}, true);
|
||||
return arr1.reduce((acc, cur) => acc && arr2.includes(cur), true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -101,7 +117,9 @@ export function isArrayContainedInOther(arr1: Array<*>, arr2: Array<*>): boolean
|
|||
* @returns {boolean}
|
||||
*/
|
||||
export function isObject(item: mixed): boolean %checks {
|
||||
return item ? (typeof item === 'object' && !Array.isArray(item) && item !== null) : false;
|
||||
return item
|
||||
? typeof item === 'object' && !Array.isArray(item) && item !== null
|
||||
: false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -126,7 +144,6 @@ export function isString(value: mixed): boolean %checks {
|
|||
export const isIOS = Platform.OS === 'ios';
|
||||
export const isAndroid = Platform.OS === 'android';
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string
|
||||
|
@ -153,16 +170,16 @@ export function tryJSONStringify(data: mixed): string | null {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// noinspection Eslint
|
||||
export const windowOrGlobal = (typeof self === 'object' && self.self === self && self) || (typeof global === 'object' && global.global === global && global) || this;
|
||||
export const windowOrGlobal =
|
||||
// eslint-disable-next-line no-restricted-globals
|
||||
(typeof self === 'object' && self.self === self && self) ||
|
||||
(typeof global === 'object' && global.global === global && global) ||
|
||||
this;
|
||||
|
||||
/**
|
||||
* No operation func
|
||||
*/
|
||||
export function noop(): void {
|
||||
}
|
||||
|
||||
export function noop(): void {}
|
||||
|
||||
// /**
|
||||
// * Delays chunks based on sizes per event loop.
|
||||
|
@ -286,7 +303,7 @@ const lastRandChars = [];
|
|||
export function generatePushID(serverTimeOffset?: number = 0): string {
|
||||
const timeStampChars = new Array(8);
|
||||
let now = new Date().getTime() + serverTimeOffset;
|
||||
const duplicateTime = (now === lastPushTime);
|
||||
const duplicateTime = now === lastPushTime;
|
||||
|
||||
lastPushTime = now;
|
||||
|
||||
|
@ -295,7 +312,8 @@ export function generatePushID(serverTimeOffset?: number = 0): string {
|
|||
now = Math.floor(now / 64);
|
||||
}
|
||||
|
||||
if (now !== 0) throw new Error('We should have converted the entire timestamp.');
|
||||
if (now !== 0)
|
||||
throw new Error('We should have converted the entire timestamp.');
|
||||
|
||||
let id = timeStampChars.join('');
|
||||
|
||||
|
@ -330,7 +348,11 @@ export function generatePushID(serverTimeOffset?: number = 0): string {
|
|||
* @param additionalProps
|
||||
* @returns {Error}
|
||||
*/
|
||||
export function nativeToJSError(code: string, message: string, additionalProps?: Object = {}) {
|
||||
export function nativeToJSError(
|
||||
code: string,
|
||||
message: string,
|
||||
additionalProps?: Object = {}
|
||||
) {
|
||||
const error: Object = new Error(message);
|
||||
error.code = code;
|
||||
Object.assign(error, additionalProps);
|
||||
|
@ -362,7 +384,6 @@ export function objectToUniqueId(object: Object): string {
|
|||
return key;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the existing promise if no callback provided or
|
||||
* exec the promise and callback if optionalCallback is valid.
|
||||
|
@ -371,10 +392,14 @@ export function objectToUniqueId(object: Object): string {
|
|||
* @param optionalCallback
|
||||
* @return {Promise}
|
||||
*/
|
||||
export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Function): Promise<*> {
|
||||
export function promiseOrCallback(
|
||||
promise: Promise<*>,
|
||||
optionalCallback?: Function
|
||||
): Promise<*> {
|
||||
if (!isFunction(optionalCallback)) return promise;
|
||||
|
||||
return promise.then((result) => {
|
||||
return promise
|
||||
.then(result => {
|
||||
// some of firebase internal tests & methods only check/return one arg
|
||||
// see https://github.com/firebase/firebase-js-sdk/blob/master/src/utils/promise.ts#L62
|
||||
if (optionalCallback && optionalCallback.length === 1) {
|
||||
|
@ -384,7 +409,8 @@ export function promiseOrCallback(promise: Promise<*>, optionalCallback?: Functi
|
|||
}
|
||||
|
||||
return Promise.resolve(result);
|
||||
}).catch((error) => {
|
||||
})
|
||||
.catch(error => {
|
||||
if (optionalCallback) optionalCallback(error);
|
||||
return Promise.reject(error);
|
||||
});
|
||||
|
@ -398,7 +424,9 @@ export function firestoreAutoId(): string {
|
|||
let autoId = '';
|
||||
|
||||
for (let i = 0; i < 20; i++) {
|
||||
autoId += AUTO_ID_CHARS.charAt(Math.floor(Math.random() * AUTO_ID_CHARS.length));
|
||||
autoId += AUTO_ID_CHARS.charAt(
|
||||
Math.floor(Math.random() * AUTO_ID_CHARS.length)
|
||||
);
|
||||
}
|
||||
return autoId;
|
||||
}
|
||||
|
|
|
@ -29,17 +29,20 @@ const PLAY_SERVICES_CODES = {
|
|||
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
|
||||
2: {
|
||||
code: 'SERVICE_VERSION_UPDATE_REQUIRED',
|
||||
message: 'The installed version of Google Play services on this device is out of date.',
|
||||
message:
|
||||
'The installed version of Google Play services on this device is out of date.',
|
||||
},
|
||||
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
|
||||
3: {
|
||||
code: 'SERVICE_DISABLED',
|
||||
message: 'The installed version of Google Play services has been disabled on this device.',
|
||||
message:
|
||||
'The installed version of Google Play services has been disabled on this device.',
|
||||
},
|
||||
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
|
||||
9: {
|
||||
code: 'SERVICE_INVALID',
|
||||
message: 'The version of the Google Play services installed on this device is not authentic.',
|
||||
message:
|
||||
'The version of the Google Play services installed on this device is not authentic.',
|
||||
},
|
||||
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
|
||||
18: {
|
||||
|
@ -49,7 +52,8 @@ const PLAY_SERVICES_CODES = {
|
|||
// $FlowBug: Doesn't like numerical object keys: https://github.com/facebook/flow/issues/380
|
||||
19: {
|
||||
code: 'SERVICE_MISSING_PERMISSION',
|
||||
message: 'Google Play service doesn\'t have one or more required permissions.',
|
||||
message:
|
||||
"Google Play service doesn't have one or more required permissions.",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -66,27 +70,33 @@ export default {
|
|||
},
|
||||
|
||||
STRINGS: {
|
||||
WARN_INITIALIZE_DEPRECATION: 'Deprecation: Calling \'initializeApp()\' for apps that are already initialised natively ' +
|
||||
'is unnecessary, use \'firebase.app()\' instead to access the already initialized default app instance.',
|
||||
WARN_INITIALIZE_DEPRECATION:
|
||||
"Deprecation: Calling 'initializeApp()' for apps that are already initialised natively " +
|
||||
"is unnecessary, use 'firebase.app()' instead to access the already initialized default app instance.",
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
get ERROR_MISSING_CORE() {
|
||||
if (Platform.OS === 'ios') {
|
||||
return 'RNFirebase core module was not found natively on iOS, ensure you have ' +
|
||||
return (
|
||||
'RNFirebase core module was not found natively on iOS, ensure you have ' +
|
||||
'correctly included the RNFirebase pod in your projects `Podfile` and have run `pod install`.' +
|
||||
'\r\n\r\n See http://invertase.link/ios for the ios setup guide.';
|
||||
'\r\n\r\n See http://invertase.link/ios for the ios setup guide.'
|
||||
);
|
||||
}
|
||||
|
||||
return 'RNFirebase core module was not found natively on Android, ensure you have ' +
|
||||
return (
|
||||
'RNFirebase core module was not found natively on Android, ensure you have ' +
|
||||
'correctly added the RNFirebase and Firebase gradle dependencies to your `android/app/build.gradle` file.' +
|
||||
'\r\n\r\n See http://invertase.link/android for the android setup guide.';
|
||||
'\r\n\r\n See http://invertase.link/android for the android setup guide.'
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
ERROR_INIT_OBJECT: 'Firebase.initializeApp(options <-- requires a valid configuration object.',
|
||||
ERROR_INIT_STRING_NAME: 'Firebase.initializeApp(options, name <-- requires a valid string value.',
|
||||
ERROR_INIT_OBJECT:
|
||||
'Firebase.initializeApp(options <-- requires a valid configuration object.',
|
||||
ERROR_INIT_STRING_NAME:
|
||||
'Firebase.initializeApp(options, name <-- requires a valid string value.',
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
|
@ -131,20 +141,28 @@ export default {
|
|||
ERROR_MISSING_MODULE(namespace: string, nativeModule: string) {
|
||||
const snippet = `firebase.${namespace}()`;
|
||||
if (Platform.OS === 'ios') {
|
||||
return `You attempted to use a firebase module that's not installed natively on your iOS project by calling ${snippet}.` +
|
||||
return (
|
||||
`You attempted to use a firebase module that's not installed natively on your iOS project by calling ${snippet}.` +
|
||||
'\r\n\r\nEnsure you have the required Firebase iOS SDK pod for this module included in your Podfile, in this instance ' +
|
||||
`confirm you've added "pod '${NAMESPACE_PODS[namespace]}'" to your Podfile` +
|
||||
'\r\n\r\nSee http://invertase.link/ios for full setup instructions.';
|
||||
`confirm you've added "pod '${
|
||||
NAMESPACE_PODS[namespace]
|
||||
}'" to your Podfile` +
|
||||
'\r\n\r\nSee http://invertase.link/ios for full setup instructions.'
|
||||
);
|
||||
}
|
||||
|
||||
const fbSDKDep = `'com.google.firebase:firebase-${GRADLE_DEPS[namespace] || namespace}'`;
|
||||
const fbSDKDep = `'com.google.firebase:firebase-${GRADLE_DEPS[
|
||||
namespace
|
||||
] || namespace}'`;
|
||||
const rnFirebasePackage = `'io.invertase.firebase.${namespace}.${nativeModule}Package'`;
|
||||
const newInstance = `'new ${nativeModule}Package()'`;
|
||||
return `You attempted to use a firebase module that's not installed on your Android project by calling ${snippet}.` +
|
||||
return (
|
||||
`You attempted to use a firebase module that's not installed on your Android project by calling ${snippet}.` +
|
||||
`\r\n\r\nEnsure you have:\r\n\r\n1) Installed the required Firebase Android SDK dependency ${fbSDKDep} in your 'android/app/build.gradle' ` +
|
||||
`file.\r\n\r\n2) Imported the ${rnFirebasePackage} module in your 'MainApplication.java' file.\r\n\r\n3) Added the ` +
|
||||
`${newInstance} line inside of the RN 'getPackages()' method list.` +
|
||||
'\r\n\r\nSee http://invertase.link/android for full setup instructions.';
|
||||
'\r\n\r\nSee http://invertase.link/android for full setup instructions.'
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -191,29 +209,30 @@ export default {
|
|||
return `firebase.${namespace}().${method}() is unsupported by the native Firebase SDKs.`;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @return {string}
|
||||
*/
|
||||
ERROR_PLAY_SERVICES(statusCode: number) {
|
||||
const knownError = PLAY_SERVICES_CODES[statusCode];
|
||||
let start = 'Google Play Services is required to run firebase services on android but a valid installation was not found on this device.';
|
||||
let start =
|
||||
'Google Play Services is required to run firebase services on android but a valid installation was not found on this device.';
|
||||
|
||||
if (statusCode === 2) {
|
||||
start = 'Google Play Services is out of date and may cause some firebase services like authentication to hang when used. It is recommended that you update it.';
|
||||
start =
|
||||
'Google Play Services is out of date and may cause some firebase services like authentication to hang when used. It is recommended that you update it.';
|
||||
}
|
||||
|
||||
// eslint-disable-next-line prefer-template
|
||||
return `${start}\r\n\r\n` +
|
||||
'-------------------------\r\n' +
|
||||
(knownError ?
|
||||
`${knownError.code}: ${knownError.message} (code ${statusCode})` :
|
||||
`A specific play store availability reason reason was not available (unknown code: ${statusCode})`
|
||||
) +
|
||||
'\r\n-------------------------' +
|
||||
'\r\n\r\n' +
|
||||
'For more information on how to resolve this issue, configure Play Services checks or for guides on how to validate Play Services on your users devices see the link below:' +
|
||||
'\r\n\r\nhttp://invertase.link/play-services';
|
||||
return (
|
||||
`${`${start}\r\n\r\n-------------------------\r\n`}${
|
||||
knownError
|
||||
? `${knownError.code}: ${knownError.message} (code ${statusCode})`
|
||||
: `A specific play store availability reason reason was not available (unknown code: ${statusCode})`
|
||||
}\r\n-------------------------` +
|
||||
`\r\n\r\n` +
|
||||
`For more information on how to resolve this issue, configure Play Services checks or for guides on how to validate Play Services on your users devices see the link below:` +
|
||||
`\r\n\r\nhttp://invertase.link/play-services`
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@ import { windowOrGlobal } from './';
|
|||
|
||||
import type ModuleBase from './ModuleBase';
|
||||
|
||||
((base) => {
|
||||
(base => {
|
||||
window = base || window;
|
||||
// $FlowFixMe: Why are we using localStorage at all?
|
||||
if (!window.localStorage) window.localStorage = {};
|
||||
|
@ -15,7 +15,8 @@ import type ModuleBase from './ModuleBase';
|
|||
|
||||
const NATIVE_LOGGERS: { [string]: Object } = {};
|
||||
|
||||
const getModuleKey = (module: ModuleBase): string => `${module.app.name}:${module.namespace}`;
|
||||
const getModuleKey = (module: ModuleBase): string =>
|
||||
`${module.app.name}:${module.namespace}`;
|
||||
|
||||
export const getLogger = (module: ModuleBase) => {
|
||||
const key = getModuleKey(module);
|
||||
|
@ -25,16 +26,18 @@ export const getLogger = (module: ModuleBase) => {
|
|||
export const initialiseLogger = (module: ModuleBase, logNamespace: string) => {
|
||||
const key = getModuleKey(module);
|
||||
if (!NATIVE_LOGGERS[key]) {
|
||||
// eslint-disable-next-line global-require
|
||||
NATIVE_LOGGERS[key] = require('bows')(`🔥 ${logNamespace.toUpperCase()}`);
|
||||
}
|
||||
};
|
||||
|
||||
export default class Log {
|
||||
static createLogger(namespace) {
|
||||
static createLogger(namespace: string) {
|
||||
// eslint-disable-next-line global-require
|
||||
return require('bows')(namespace);
|
||||
}
|
||||
|
||||
static setLevel(booleanOrDebugString) {
|
||||
static setLevel(booleanOrDebugString: boolean | string) {
|
||||
window.localStorage.debug = booleanOrDebugString;
|
||||
window.localStorage.debugColors = !!booleanOrDebugString;
|
||||
}
|
||||
|
|
|
@ -8,14 +8,6 @@ import INTERNALS from './internals';
|
|||
import type ModuleBase from './ModuleBase';
|
||||
import type { FirebaseModuleConfig } from '../types';
|
||||
|
||||
// Firebase Native SDKs that support multiple app instances
|
||||
const MULTI_APP_MODULES = [
|
||||
'RNFirebaseAuth',
|
||||
'RNFirebaseDatabase',
|
||||
'RNFirebaseFirestore',
|
||||
'RNFirebaseStorage',
|
||||
];
|
||||
|
||||
const NATIVE_MODULES: { [string]: Object } = {};
|
||||
|
||||
/**
|
||||
|
@ -29,36 +21,40 @@ const nativeWithApp = (appName: string, NativeModule: Object): Object => {
|
|||
|
||||
for (let i = 0, len = methods.length; i < len; i++) {
|
||||
const method = methods[i];
|
||||
native[method] = (...args) => {
|
||||
return NativeModule[method](...[appName, ...args]);
|
||||
};
|
||||
native[method] = (...args) => NativeModule[method](...[appName, ...args]);
|
||||
}
|
||||
|
||||
return native;
|
||||
};
|
||||
|
||||
const getModuleKey = (module: ModuleBase): string => `${module.app.name}:${module.namespace}`;
|
||||
const getModuleKey = (module: ModuleBase): string =>
|
||||
`${module.app.name}:${module.namespace}`;
|
||||
|
||||
export const getNativeModule = (module: ModuleBase): Object => {
|
||||
const key = getModuleKey(module);
|
||||
return NATIVE_MODULES[key];
|
||||
};
|
||||
|
||||
export const initialiseNativeModule = (module: ModuleBase, config: FirebaseModuleConfig): Object => {
|
||||
const { moduleName, namespace } = config;
|
||||
export const initialiseNativeModule = (
|
||||
module: ModuleBase,
|
||||
config: FirebaseModuleConfig
|
||||
): Object => {
|
||||
const { moduleName, multiApp, namespace } = config;
|
||||
const nativeModule = NativeModules[moduleName];
|
||||
const key = getModuleKey(module);
|
||||
|
||||
if (!nativeModule && namespace !== 'utils') {
|
||||
throw new Error(INTERNALS.STRINGS.ERROR_MISSING_MODULE(namespace, moduleName));
|
||||
throw new Error(
|
||||
INTERNALS.STRINGS.ERROR_MISSING_MODULE(namespace, moduleName)
|
||||
);
|
||||
}
|
||||
|
||||
// used by the modules that extend ModuleBase
|
||||
// to access their native module counterpart
|
||||
if (!MULTI_APP_MODULES.includes(moduleName)) {
|
||||
NATIVE_MODULES[key] = nativeModule;
|
||||
} else {
|
||||
if (multiApp) {
|
||||
NATIVE_MODULES[key] = nativeWithApp(module.app.name, nativeModule);
|
||||
} else {
|
||||
NATIVE_MODULES[key] = nativeModule;
|
||||
}
|
||||
|
||||
initialiseNativeModuleEventEmitter(module, config);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
73
package.json
73
package.json
|
@ -1,25 +1,29 @@
|
|||
{
|
||||
"name": "react-native-firebase",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.4",
|
||||
"author": "Invertase <contact@invertase.io> (http://invertase.io)",
|
||||
"description": "A well tested, feature rich Firebase implementation for React Native, supporting iOS & Android. Individual module support for Admob, Analytics, Auth, Crash Reporting, Cloud Firestore, Database, Dynamic Links, Messaging (FCM), Remote Config, Storage and Performance.",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "npm run build-lib && npm run build-flow",
|
||||
"build": "genversion lib/version.js && npm run validate-ts-declarations && npm run build-lib && npm run build-flow",
|
||||
"build-flow": "flow-copy-source -i */__tests__* lib dist",
|
||||
"build-lib": "BABEL_ENV=publish babel lib -d dist --ignore __tests__ --copy-files",
|
||||
"clean": "rimraf dist/",
|
||||
"flow": "flow",
|
||||
"lint": "eslint ./src",
|
||||
"format:assets": "prettier --ignore-path .gitignore --write \"**/*.{json,md}\"",
|
||||
"format": "npm run format:assets && npm run lint -- --fix",
|
||||
"lint": "eslint ./lib ./tests/src ./tests/lib",
|
||||
"precommit": "lint-staged",
|
||||
"prepublish": "npm run clean && npm run build",
|
||||
"postinstall": "postinstall-build dist && opencollective postinstall",
|
||||
"postinstall": "postinstall-build dist && opencollective postinstall || exit 0",
|
||||
"test-cli": "node ./bin/test.js",
|
||||
"tests-packager": "cd tests && npm run start",
|
||||
"tests-npm-install": "cd tests && npm install",
|
||||
"tests-pod-install": "cd tests && npm run ios:pod:install",
|
||||
"tests-watch-start": "npm run test-cli watch init start",
|
||||
"tests-watch-stop": "npm run test-cli watch stop"
|
||||
"tests-watch-stop": "npm run test-cli watch stop",
|
||||
"validate-ts-declarations": "tsc --project ./"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
@ -28,45 +32,10 @@
|
|||
"jest": {
|
||||
"preset": "jest-react-native",
|
||||
"setupFiles": [],
|
||||
"unmockedModulePathPatterns": [
|
||||
"./node_modules/react",
|
||||
"./node_modules/react-native",
|
||||
"./node_modules/react-native-mock",
|
||||
"./node_modules/react-addons-test-utils"
|
||||
]
|
||||
"unmockedModulePathPatterns": ["./node_modules/react", "./node_modules/react-native", "./node_modules/react-native-mock", "./node_modules/react-addons-test-utils"]
|
||||
},
|
||||
"license": "APACHE-2.0",
|
||||
"keywords": [
|
||||
"react",
|
||||
"admob",
|
||||
"auth",
|
||||
"config",
|
||||
"digits",
|
||||
"phone-auth",
|
||||
"sms",
|
||||
"firestore",
|
||||
"cloud-firestore",
|
||||
"datastore",
|
||||
"remote-config",
|
||||
"transactions",
|
||||
"react-native",
|
||||
"react-native-firebase",
|
||||
"firebase",
|
||||
"fcm",
|
||||
"apn",
|
||||
"gcm",
|
||||
"analytics",
|
||||
"messaging",
|
||||
"database",
|
||||
"android",
|
||||
"ios",
|
||||
"crash",
|
||||
"firestack",
|
||||
"performance",
|
||||
"firestore",
|
||||
"dynamic-links",
|
||||
"crashlytics"
|
||||
],
|
||||
"keywords": ["react", "admob", "auth", "config", "digits", "phone-auth", "sms", "firestore", "cloud-firestore", "datastore", "remote-config", "transactions", "react-native", "react-native-firebase", "firebase", "fcm", "apn", "gcm", "analytics", "messaging", "database", "android", "ios", "crash", "firestack", "performance", "firestore", "dynamic-links", "crashlytics"],
|
||||
"peerDependencies": {
|
||||
"react": "*",
|
||||
"react-native": ">= 0.48.0",
|
||||
|
@ -82,17 +51,24 @@
|
|||
"enzyme": "^2.4.1",
|
||||
"eslint": "^4.11.0",
|
||||
"eslint-config-airbnb": "^16.1.0",
|
||||
"eslint-config-prettier": "^2.9.0",
|
||||
"eslint-plugin-flowtype": "^2.39.1",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-jsx-a11y": "^6.0.2",
|
||||
"eslint-plugin-prettier": "^2.5.0",
|
||||
"eslint-plugin-react": "^7.4.0",
|
||||
"flow-bin": "^0.56.0",
|
||||
"flow-bin": "^0.61.0",
|
||||
"flow-copy-source": "^1.2.1",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-native": "^0.50.3",
|
||||
"genversion": "^2.0.1",
|
||||
"husky": "^0.14.3",
|
||||
"lint-staged": "^6.0.1",
|
||||
"prettier": "1.10.2",
|
||||
"react": "^16.2.0",
|
||||
"react-dom": "^16.2.0",
|
||||
"react-native": "^0.52.0",
|
||||
"rimraf": "^2.6.2",
|
||||
"shelljs": "^0.7.8",
|
||||
"typescript": "^2.6.2",
|
||||
"wml": "0.0.82"
|
||||
},
|
||||
"dependencies": {
|
||||
|
@ -115,5 +91,10 @@
|
|||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/react-native-firebase",
|
||||
"logo": "https://opencollective.com/opencollective/logo.txt"
|
||||
},
|
||||
"lint-staged": {
|
||||
"lib/**/*.js": ["eslint --fix", "git add"],
|
||||
"tests/{src|lib}/**/*.js": ["eslint --fix", "git add"],
|
||||
"*.{json,md,scss}": ["prettier --write", "git add"]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
module.exports = {
|
||||
trailingComma: 'es5',
|
||||
singleQuote: true,
|
||||
overrides: [
|
||||
{
|
||||
files: '*.json',
|
||||
options: {
|
||||
printWidth: 400,
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
|
@ -1,42 +1,39 @@
|
|||
{
|
||||
"extends": "airbnb",
|
||||
"extends": [
|
||||
"airbnb",
|
||||
"prettier",
|
||||
"prettier/flowtype",
|
||||
"prettier/react"
|
||||
],
|
||||
"parser": "babel-eslint",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
},
|
||||
"plugins": [
|
||||
"flowtype"
|
||||
"flowtype",
|
||||
"prettier"
|
||||
],
|
||||
"env": {
|
||||
"es6": true,
|
||||
"jasmine": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"no-plusplus": 0,
|
||||
"prettier/prettier": ["error", {
|
||||
"trailingComma": "es5",
|
||||
"singleQuote": true
|
||||
}],
|
||||
|
||||
"react/forbid-prop-types": "warn",
|
||||
"react/jsx-filename-extension": [
|
||||
"off", { "extensions": [".js", ".jsx"] }
|
||||
],
|
||||
|
||||
"class-methods-use-this": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"no-use-before-define": 0,
|
||||
"arrow-body-style": 0,
|
||||
"import/prefer-default-export": 0,
|
||||
"radix": 0,
|
||||
"new-cap": 0,
|
||||
"max-len": 0,
|
||||
"no-continue": 0,
|
||||
"no-console": 0,
|
||||
"global-require": 0,
|
||||
"import/extensions": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"react/jsx-filename-extension": 0
|
||||
"no-plusplus": 0,
|
||||
"no-undef": 0,
|
||||
"no-underscore-dangle": "off",
|
||||
"no-use-before-define": 0
|
||||
},
|
||||
"globals": {
|
||||
"__DEV__": true,
|
||||
"window": true,
|
||||
"fetch": true,
|
||||
"window": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,36 +12,45 @@
|
|||
; For RN Apps installed via npm, "Libraries" folder is inside
|
||||
; "node_modules/react-native" but in the source repo it is in the root
|
||||
.*/Libraries/react-native/React.js
|
||||
.*/Libraries/react-native/ReactNative.js
|
||||
|
||||
; Ignore polyfills
|
||||
.*/Libraries/polyfills/.*
|
||||
|
||||
; Ignore metro
|
||||
.*/node_modules/metro/.*
|
||||
|
||||
[include]
|
||||
|
||||
[libs]
|
||||
node_modules/react-native/Libraries/react-native/react-native-interface.js
|
||||
node_modules/react-native/flow
|
||||
flow/
|
||||
node_modules/react-native/flow/
|
||||
node_modules/react-native/flow-github/
|
||||
|
||||
[options]
|
||||
emoji=true
|
||||
|
||||
module.system=haste
|
||||
|
||||
experimental.strict_type_args=true
|
||||
|
||||
munge_underscores=true
|
||||
|
||||
module.name_mapper='^~\/\(.*\)$' -> '<PROJECT_ROOT>/\1'
|
||||
module.name_mapper='^[./a-zA-Z0-9$_-]+\.\(bmp\|gif\|jpg\|jpeg\|png\|psd\|svg\|webp\|m4v\|mov\|mp4\|mpeg\|mpg\|webm\|aac\|aiff\|caf\|m4a\|mp3\|wav\|html\|pdf\)$' -> 'RelativeImageStub'
|
||||
|
||||
module.file_ext=.js
|
||||
module.file_ext=.jsx
|
||||
module.file_ext=.json
|
||||
module.file_ext=.native.js
|
||||
|
||||
suppress_type=$FlowIssue
|
||||
suppress_type=$FlowFixMe
|
||||
suppress_type=$FixMe
|
||||
suppress_type=$FlowFixMeProps
|
||||
suppress_type=$FlowFixMeState
|
||||
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(>=0\\.\\(3[0-8]\\|[1-2][0-9]\\|[0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(>=0\\.\\(3[0-8]\\|1[0-9]\\|[1-2][0-9]\\).[0-9]\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixMe\\($\\|[^(]\\|(\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowIssue\\((\\(<VERSION>\\)? *\\(site=[a-z,_]*react_native[a-z,_]*\\)?)\\)?:? #[0-9]+
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowFixedInNextDeploy
|
||||
suppress_comment=\\(.\\|\n\\)*\\$FlowExpectedError
|
||||
|
||||
unsafe.enable_getters_and_setters=true
|
||||
|
||||
[version]
|
||||
^0.38.0
|
||||
^0.61.0
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import re
|
||||
|
||||
# To learn about Buck see [Docs](https://buckbuild.com/).
|
||||
# To run your application with Buck:
|
||||
# - install Buck
|
||||
|
@ -11,8 +9,9 @@ import re
|
|||
#
|
||||
|
||||
lib_deps = []
|
||||
|
||||
for jarfile in glob(['libs/*.jar']):
|
||||
name = 'jars__' + re.sub(r'^.*/([^/]+)\.jar$', r'\1', jarfile)
|
||||
name = 'jars__' + jarfile[jarfile.rindex('/') + 1: jarfile.rindex('.jar')]
|
||||
lib_deps.append(':' + name)
|
||||
prebuilt_jar(
|
||||
name = name,
|
||||
|
@ -20,7 +19,7 @@ for jarfile in glob(['libs/*.jar']):
|
|||
)
|
||||
|
||||
for aarfile in glob(['libs/*.aar']):
|
||||
name = 'aars__' + re.sub(r'^.*/([^/]+)\.aar$', r'\1', aarfile)
|
||||
name = 'aars__' + aarfile[aarfile.rindex('/') + 1: aarfile.rindex('.aar')]
|
||||
lib_deps.append(':' + name)
|
||||
android_prebuilt_aar(
|
||||
name = name,
|
||||
|
@ -28,39 +27,39 @@ for aarfile in glob(['libs/*.aar']):
|
|||
)
|
||||
|
||||
android_library(
|
||||
name = 'all-libs',
|
||||
exported_deps = lib_deps
|
||||
name = "all-libs",
|
||||
exported_deps = lib_deps,
|
||||
)
|
||||
|
||||
android_library(
|
||||
name = 'app-code',
|
||||
name = "app-code",
|
||||
srcs = glob([
|
||||
'src/main/java/**/*.java',
|
||||
"src/main/java/**/*.java",
|
||||
]),
|
||||
deps = [
|
||||
':all-libs',
|
||||
':build_config',
|
||||
':res',
|
||||
":all-libs",
|
||||
":build_config",
|
||||
":res",
|
||||
],
|
||||
)
|
||||
|
||||
android_build_config(
|
||||
name = 'build_config',
|
||||
package = 'com.reactnativefirebasedemo',
|
||||
name = "build_config",
|
||||
package = "com.react-native-firebase-tests",
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = 'res',
|
||||
res = 'src/main/res',
|
||||
package = 'com.reactnativefirebasedemo',
|
||||
name = "res",
|
||||
package = "com.react-native-firebase-tests",
|
||||
res = "src/main/res",
|
||||
)
|
||||
|
||||
android_binary(
|
||||
name = 'app',
|
||||
package_type = 'debug',
|
||||
manifest = 'src/main/AndroidManifest.xml',
|
||||
keystore = '//android/keystores:debug',
|
||||
name = "app",
|
||||
keystore = "//android/keystores:debug",
|
||||
manifest = "src/main/AndroidManifest.xml",
|
||||
package_type = "debug",
|
||||
deps = [
|
||||
':app-code',
|
||||
":app-code",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -4,11 +4,78 @@ apply plugin: 'io.fabric'
|
|||
|
||||
import com.android.build.OutputFile
|
||||
|
||||
/**
|
||||
* The react.gradle file registers a task for each build variant (e.g. bundleDebugJsAndAssets
|
||||
* and bundleReleaseJsAndAssets).
|
||||
* These basically call `react-native bundle` with the correct arguments during the Android build
|
||||
* cycle. By default, bundleDebugJsAndAssets is skipped, as in debug/dev mode we prefer to load the
|
||||
* bundle directly from the development server. Below you can see all the possible configurations
|
||||
* and their defaults. If you decide to add a configuration block, make sure to add it before the
|
||||
* `apply from: "../../node_modules/react-native/react.gradle"` line.
|
||||
*
|
||||
* project.ext.react = [
|
||||
* // the name of the generated asset file containing your JS bundle
|
||||
* bundleAssetName: "index.android.bundle",
|
||||
*
|
||||
* // the entry file for bundle generation
|
||||
* entryFile: "index.android.js",
|
||||
*
|
||||
* // whether to bundle JS and assets in debug mode
|
||||
* bundleInDebug: false,
|
||||
*
|
||||
* // whether to bundle JS and assets in release mode
|
||||
* bundleInRelease: true,
|
||||
*
|
||||
* // whether to bundle JS and assets in another build variant (if configured).
|
||||
* // See http://tools.android.com/tech-docs/new-build-system/user-guide#TOC-Build-Variants
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'bundleIn${productFlavor}${buildType}'
|
||||
* // 'bundleIn${buildType}'
|
||||
* // bundleInFreeDebug: true,
|
||||
* // bundleInPaidRelease: true,
|
||||
* // bundleInBeta: true,
|
||||
*
|
||||
* // whether to disable dev mode in custom build variants (by default only disabled in release)
|
||||
* // for example: to disable dev mode in the staging build type (if configured)
|
||||
* devDisabledInStaging: true,
|
||||
* // The configuration property can be in the following formats
|
||||
* // 'devDisabledIn${productFlavor}${buildType}'
|
||||
* // 'devDisabledIn${buildType}'
|
||||
*
|
||||
* // the root of your project, i.e. where "package.json" lives
|
||||
* root: "../../",
|
||||
*
|
||||
* // where to put the JS bundle asset in debug mode
|
||||
* jsBundleDirDebug: "$buildDir/intermediates/assets/debug",
|
||||
*
|
||||
* // where to put the JS bundle asset in release mode
|
||||
* jsBundleDirRelease: "$buildDir/intermediates/assets/release",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in debug mode
|
||||
* resourcesDirDebug: "$buildDir/intermediates/res/merged/debug",
|
||||
*
|
||||
* // where to put drawable resources / React Native assets, e.g. the ones you use via
|
||||
* // require('./image.png')), in release mode
|
||||
* resourcesDirRelease: "$buildDir/intermediates/res/merged/release",
|
||||
*
|
||||
* // by default the gradle tasks are skipped if none of the JS files or assets change; this means
|
||||
* // that we don't look at files in android/ or ios/ to determine whether the tasks are up to
|
||||
* // date; if you have any other folders that you want to ignore for performance reasons (gradle
|
||||
* // indexes the entire tree), add them here. Alternatively, if you have JS files in android/
|
||||
* // for example, you might want to remove it from here.
|
||||
* inputExcludes: ["android/**", "ios/**"],
|
||||
*
|
||||
* // override which node gets called and with what additional arguments
|
||||
* nodeExecutableAndArgs: ["node"],
|
||||
*
|
||||
* // supply additional arguments to the packager
|
||||
* extraPackagerArgs: []
|
||||
* ]
|
||||
*/
|
||||
|
||||
project.ext.react = [
|
||||
// whether to bundle JS and assets in staging mode
|
||||
bundleInDebug : false,
|
||||
jsBundleDirDebug : "$buildDir/intermediates/assets/debug",
|
||||
nodeExecutableAndArgs: ["/usr/local/bin/node"]
|
||||
entryFile: "index.js"
|
||||
]
|
||||
|
||||
apply from: "../../node_modules/react-native/react.gradle"
|
||||
|
@ -63,7 +130,7 @@ android {
|
|||
variant.outputs.each { output ->
|
||||
// For each separate APK per architecture, set a unique version code as described here:
|
||||
// http://tools.android.com/tech-docs/new-build-system/user-guide/apk-splits
|
||||
def versionCodes = ["armeabi-v7a": 1, "x86": 2]
|
||||
def versionCodes = ["armeabi-v7a":1, "x86":2]
|
||||
def abi = output.getFilter(OutputFile.ABI)
|
||||
if (abi != null) { // null for the universal-debug, universal-release variants
|
||||
output.versionCodeOverride =
|
||||
|
@ -73,14 +140,13 @@ android {
|
|||
}
|
||||
}
|
||||
|
||||
project.ext.firebaseVersion = '11.6.2'
|
||||
project.ext.firebaseVersion = '11.8.0'
|
||||
|
||||
dependencies {
|
||||
// compile(project(':react-native-firebase')) {
|
||||
// transitive = false
|
||||
// }
|
||||
compile project(':react-native-vector-icons')
|
||||
compile project(':react-native-firebase')
|
||||
compile(project(':react-native-firebase')) {
|
||||
transitive = false
|
||||
}
|
||||
compile fileTree(dir: "libs", include: ["*.jar"])
|
||||
compile "com.google.android.gms:play-services-base:$firebaseVersion"
|
||||
compile "com.google.firebase:firebase-ads:$firebaseVersion"
|
||||
|
|
|
@ -50,6 +50,10 @@
|
|||
|
||||
-dontwarn com.facebook.react.**
|
||||
|
||||
# TextLayoutBuilder uses a non-public Android constructor within StaticLayout.
|
||||
# See libs/proxy/src/main/java/com/facebook/fbui/textlayoutbuilder/proxy for details.
|
||||
-dontwarn android.text.StaticLayout
|
||||
|
||||
# okhttp
|
||||
|
||||
-keepattributes Signature
|
||||
|
|
|
@ -53,6 +53,11 @@ public class MainApplication extends Application implements ReactApplication {
|
|||
new RNFirebaseStoragePackage()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getJSMainModuleName() {
|
||||
return "index";
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
#Tue Mar 07 13:10:12 GMT 2017
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
|
@ -42,6 +42,11 @@ case "`uname`" in
|
|||
;;
|
||||
esac
|
||||
|
||||
# For Cygwin, ensure paths are in UNIX format before anything is touched.
|
||||
if $cygwin ; then
|
||||
[ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
|
||||
fi
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
# Resolve links: $0 may be a link
|
||||
PRG="$0"
|
||||
|
@ -56,9 +61,9 @@ while [ -h "$PRG" ] ; do
|
|||
fi
|
||||
done
|
||||
SAVED="`pwd`"
|
||||
cd "`dirname \"$PRG\"`/" >/dev/null
|
||||
cd "`dirname \"$PRG\"`/" >&-
|
||||
APP_HOME="`pwd -P`"
|
||||
cd "$SAVED" >/dev/null
|
||||
cd "$SAVED" >&-
|
||||
|
||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
|
@ -109,7 +114,6 @@ fi
|
|||
if $cygwin ; then
|
||||
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
|
||||
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
|
||||
JAVACMD=`cygpath --unix "$JAVACMD"`
|
||||
|
||||
# We build the pattern for arguments to be converted via cygpath
|
||||
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
keystore(
|
||||
name = 'debug',
|
||||
store = 'debug.keystore',
|
||||
properties = 'debug.keystore.properties',
|
||||
name = "debug",
|
||||
properties = "debug.keystore.properties",
|
||||
store = "debug.keystore",
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
"PUBLIC",
|
||||
],
|
||||
)
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
import { AppRegistry } from 'react-native';
|
||||
import bootstrap from './src/main';
|
||||
|
||||
AppRegistry.registerComponent('ReactNativeFirebaseDemo', () => bootstrap);
|
||||
|
|
@ -1,5 +1,4 @@
|
|||
import { AppRegistry } from 'react-native';
|
||||
import bootstrap from './src/main';
|
||||
|
||||
|
||||
AppRegistry.registerComponent('ReactNativeFirebaseDemo', () => bootstrap);
|
|
@ -40,6 +40,12 @@ target 'ReactNativeFirebaseDemo' do
|
|||
if target.name == "React"
|
||||
target.remove_from_project
|
||||
end
|
||||
if target.name == 'yoga'
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'NO'
|
||||
config.build_settings['GCC_WARN_64_TO_32_BIT_CONVERSION'] = 'NO'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,231 +0,0 @@
|
|||
PODS:
|
||||
- BoringSSL (9.1):
|
||||
- BoringSSL/Implementation (= 9.1)
|
||||
- BoringSSL/Interface (= 9.1)
|
||||
- BoringSSL/Implementation (9.1):
|
||||
- BoringSSL/Interface (= 9.1)
|
||||
- BoringSSL/Interface (9.1)
|
||||
- Crashlytics (3.9.3):
|
||||
- Fabric (~> 1.7.2)
|
||||
- Fabric (1.7.2)
|
||||
- Firebase/AdMob (4.5.0):
|
||||
- Firebase/Core
|
||||
- Google-Mobile-Ads-SDK (= 7.25.0)
|
||||
- Firebase/Auth (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseAuth (= 4.3.1)
|
||||
- Firebase/Core (4.5.0):
|
||||
- FirebaseAnalytics (= 4.0.4)
|
||||
- FirebaseCore (= 4.0.10)
|
||||
- Firebase/Crash (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseCrash (= 2.0.2)
|
||||
- Firebase/Database (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDatabase (= 4.1.0)
|
||||
- Firebase/DynamicLinks (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDynamicLinks (= 2.1.0)
|
||||
- Firebase/Firestore (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseFirestore (= 0.9.1)
|
||||
- Firebase/Messaging (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseMessaging (= 2.0.6)
|
||||
- Firebase/Performance (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebasePerformance (= 1.0.6)
|
||||
- Firebase/RemoteConfig (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseRemoteConfig (= 2.1.0)
|
||||
- Firebase/Storage (4.5.0):
|
||||
- Firebase/Core
|
||||
- FirebaseStorage (= 2.0.2)
|
||||
- FirebaseABTesting (1.0.0):
|
||||
- FirebaseCore (~> 4.0)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseAnalytics (4.0.4):
|
||||
- FirebaseCore (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- nanopb (~> 0.3)
|
||||
- FirebaseAuth (4.3.1):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- FirebaseCore (4.0.10):
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- nanopb (~> 0.3)
|
||||
- FirebaseCrash (2.0.2):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseDatabase (4.1.0):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- leveldb-library (~> 1.18)
|
||||
- FirebaseDynamicLinks (2.1.0):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseFirestore (0.9.1):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseAuth (~> 4.3)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- gRPC-ProtoRPC (~> 1.0)
|
||||
- leveldb-library (~> 1.18)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseInstanceID (2.0.5)
|
||||
- FirebaseMessaging (2.0.6):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebasePerformance (1.0.6):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseRemoteConfig (2.1.0):
|
||||
- FirebaseABTesting (~> 1.0)
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseInstanceID (~> 2.0)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseStorage (2.0.2):
|
||||
- FirebaseAnalytics (~> 4.0)
|
||||
- FirebaseCore (~> 4.0)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- Google-Mobile-Ads-SDK (7.25.0)
|
||||
- GoogleToolboxForMac/DebugUtils (2.1.3):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.3)
|
||||
- GoogleToolboxForMac/Defines (2.1.3)
|
||||
- GoogleToolboxForMac/Logger (2.1.3):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.3)
|
||||
- GoogleToolboxForMac/NSData+zlib (2.1.3):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.3)
|
||||
- GoogleToolboxForMac/NSDictionary+URLArguments (2.1.3):
|
||||
- GoogleToolboxForMac/DebugUtils (= 2.1.3)
|
||||
- GoogleToolboxForMac/Defines (= 2.1.3)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.3)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (2.1.3)
|
||||
- gRPC (1.7.0):
|
||||
- gRPC-RxLibrary (= 1.7.0)
|
||||
- gRPC/Main (= 1.7.0)
|
||||
- gRPC-Core (1.7.0):
|
||||
- gRPC-Core/Implementation (= 1.7.0)
|
||||
- gRPC-Core/Interface (= 1.7.0)
|
||||
- gRPC-Core/Implementation (1.7.0):
|
||||
- BoringSSL (~> 9.0)
|
||||
- gRPC-Core/Interface (= 1.7.0)
|
||||
- nanopb (~> 0.3)
|
||||
- gRPC-Core/Interface (1.7.0)
|
||||
- gRPC-ProtoRPC (1.7.0):
|
||||
- gRPC (= 1.7.0)
|
||||
- gRPC-RxLibrary (= 1.7.0)
|
||||
- Protobuf (~> 3.0)
|
||||
- gRPC-RxLibrary (1.7.0)
|
||||
- gRPC/Main (1.7.0):
|
||||
- gRPC-Core (= 1.7.0)
|
||||
- gRPC-RxLibrary (= 1.7.0)
|
||||
- GTMSessionFetcher/Core (1.1.12)
|
||||
- leveldb-library (1.20)
|
||||
- nanopb (0.3.8):
|
||||
- nanopb/decode (= 0.3.8)
|
||||
- nanopb/encode (= 0.3.8)
|
||||
- nanopb/decode (0.3.8)
|
||||
- nanopb/encode (0.3.8)
|
||||
- Protobuf (3.4.0)
|
||||
- React (0.49.1):
|
||||
- React/Core (= 0.49.1)
|
||||
- React/BatchedBridge (0.49.1):
|
||||
- React/Core
|
||||
- React/cxxreact_legacy
|
||||
- React/Core (0.49.1):
|
||||
- yoga (= 0.49.1.React)
|
||||
- React/cxxreact_legacy (0.49.1):
|
||||
- React/jschelpers_legacy
|
||||
- React/fishhook (0.49.1)
|
||||
- React/jschelpers_legacy (0.49.1)
|
||||
- React/RCTBlob (0.49.1):
|
||||
- React/Core
|
||||
- React/RCTNetwork (0.49.1):
|
||||
- React/Core
|
||||
- React/RCTText (0.49.1):
|
||||
- React/Core
|
||||
- React/RCTWebSocket (0.49.1):
|
||||
- React/Core
|
||||
- React/fishhook
|
||||
- React/RCTBlob
|
||||
- RNFirebase (3.2.0):
|
||||
- React
|
||||
- yoga (0.49.1.React)
|
||||
|
||||
DEPENDENCIES:
|
||||
- Crashlytics (~> 3.9.3)
|
||||
- Fabric (~> 1.7.2)
|
||||
- Firebase/AdMob
|
||||
- Firebase/Auth
|
||||
- Firebase/Core
|
||||
- Firebase/Crash
|
||||
- Firebase/Database
|
||||
- Firebase/DynamicLinks
|
||||
- Firebase/Firestore
|
||||
- Firebase/Messaging
|
||||
- Firebase/Performance
|
||||
- Firebase/RemoteConfig
|
||||
- Firebase/Storage
|
||||
- React/BatchedBridge (from `../node_modules/react-native`)
|
||||
- React/Core (from `../node_modules/react-native`)
|
||||
- React/RCTNetwork (from `../node_modules/react-native`)
|
||||
- React/RCTText (from `../node_modules/react-native`)
|
||||
- React/RCTWebSocket (from `../node_modules/react-native`)
|
||||
- RNFirebase (from `../../ios/RNFirebase.podspec`)
|
||||
- yoga (from `../node_modules/react-native/ReactCommon/yoga`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
React:
|
||||
:path: ../node_modules/react-native
|
||||
RNFirebase:
|
||||
:path: ../../ios/RNFirebase.podspec
|
||||
yoga:
|
||||
:path: ../node_modules/react-native/ReactCommon/yoga
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
BoringSSL: 84318770d120503ab1a6aaf1df777c5ca053697e
|
||||
Crashlytics: dbb07d01876c171c5ccbdf7826410380189e452c
|
||||
Fabric: 9cd6a848efcf1b8b07497e0b6a2e7d336353ba15
|
||||
Firebase: d83d287bdb6b1c78320561482706d1fcfc8ddfc1
|
||||
FirebaseABTesting: d07d0ee833b842d5153549e4c7e2e2cb1c23a3f9
|
||||
FirebaseAnalytics: 722b53c7b32bfc7806b06e0093a2f5180d4f2c5a
|
||||
FirebaseAuth: e7c2b1359c2df4af23a568100a8eace0b8c507e4
|
||||
FirebaseCore: da5e8e372cb6046212739a4d81e42d32c22907cc
|
||||
FirebaseCrash: cded0fc566c03651aea606a101bc156085f333ca
|
||||
FirebaseDatabase: 607284a103e961d7f5863ee603cab5e85f443bd6
|
||||
FirebaseDynamicLinks: ed4cb6c42705aaa5e841ed2d76e3a4bddbec10c1
|
||||
FirebaseFirestore: 2112e800ec742daa37b3500b227aaa13e7ca236c
|
||||
FirebaseInstanceID: f2b688c66b972f30d7fa9f5f9f91455454a03b47
|
||||
FirebaseMessaging: 75d83375b0f7a9911568d7bdd1a1a8261cbcbdef
|
||||
FirebasePerformance: fa032c27e229eb8c1a8638918793fe2e47465205
|
||||
FirebaseRemoteConfig: 451fe8e9c43ac1e7a137ad2a42189bfc8c2c3ebc
|
||||
FirebaseStorage: 0cca42d9b889a0227c3a50121f45a4469fc9eb27
|
||||
Google-Mobile-Ads-SDK: 113804f266381a30f982ad3c18063d4e0155414f
|
||||
GoogleToolboxForMac: 2501e2ad72a52eb3dfe7bd9aee7dad11b858bd20
|
||||
gRPC: 4322828abb82ceee683b8205c352143e15ba4cef
|
||||
gRPC-Core: 156780506d5e9b1b4487a108e8e8eb5bd966da22
|
||||
gRPC-ProtoRPC: cb11e31dba9a17fed05988c59504c6db77838746
|
||||
gRPC-RxLibrary: d13658486ddda3d31a460c17a5f012a6797b608f
|
||||
GTMSessionFetcher: ebaa1f79a5366922c1735f1566901f50beba23b7
|
||||
leveldb-library: 9e29a1d913f922444127a7d0f28b025a0e2ba053
|
||||
nanopb: 5601e6bca2dbf1ed831b519092ec110f66982ca3
|
||||
Protobuf: 03eef2ee0b674770735cf79d9c4d3659cf6908e8
|
||||
React: cf892fb84b7d06bf5fea7f328e554c6dcabe85ee
|
||||
RNFirebase: 22b1917fec663706907bc901ed665ac4f8b9bfd6
|
||||
yoga: 3abf02d6d9aeeb139b4c930eb1367feae690a35a
|
||||
|
||||
PODFILE CHECKSUM: f17a538903249834df5049668d10174810db4c4c
|
||||
|
||||
COCOAPODS: 1.3.1
|
|
@ -19,7 +19,7 @@
|
|||
{
|
||||
[FIRApp configure];
|
||||
NSURL *jsCodeLocation;
|
||||
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
|
||||
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
|
||||
|
||||
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
|
||||
moduleName:@"ReactNativeFirebaseDemo"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue