├── .Rbuildignore ├── .Rprofile ├── .gitattributes ├── .github ├── .gitignore ├── ISSUE_TEMPLATE │ └── security-issue.md └── workflows │ ├── R-CMD-check.yaml │ └── packer-check.yml ├── .gitignore ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── CRAN-SUBMISSION ├── DESCRIPTION ├── LICENSE.md ├── NAMESPACE ├── NEWS.md ├── R ├── class-analytics.R ├── class-auth.R ├── class-core.R ├── class-email-link.R ├── class-email-password.R ├── class-oauth.R ├── class-phone.R ├── class-real-time.R ├── class-social.R ├── class-storage.R ├── class-ui.R ├── config.R ├── dependencies.R ├── toggle.R └── utils.R ├── README.md ├── SECURITY.md ├── appveyor.yml ├── cran-comments.md ├── docs ├── .nojekyll ├── 404.html ├── CODE_OF_CONDUCT.html ├── LICENSE.html ├── SECURITY.html ├── apple-touch-icon-120x120.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon.png ├── articles │ ├── analytics.html │ ├── demo.html │ ├── email-link.html │ ├── email-password.html │ ├── firebase_email_password.gif │ ├── firebase_redirect.png │ ├── firebase_yahoo.png │ ├── fireblaze_github.png │ ├── fireblaze_github_popup.png │ ├── fireblaze_google.png │ ├── fireblaze_home.png │ ├── fireblaze_project.png │ ├── fireblaze_signin_method.png │ ├── fireblaze_social.gif │ ├── fireblaze_step_1.png │ ├── fireblaze_step_2.png │ ├── fireblaze_users.png │ ├── fireblazer_project_setup1.png │ ├── flow.html │ ├── get-started.html │ ├── github_oauth.png │ ├── index.html │ ├── manage.html │ ├── oauth-providers.html │ ├── phone.html │ ├── social.html │ ├── state-persistence.html │ ├── storage.html │ ├── ui.html │ └── ui_simple.png ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── docsearch.css ├── docsearch.js ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── link.svg ├── logo.png ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── Analytics.html │ ├── Firebase.html │ ├── FirebaseAuth.html │ ├── FirebaseEmailLink.html │ ├── FirebaseEmailPassword.html │ ├── FirebaseOauthProviders.html │ ├── FirebasePhone.html │ ├── FirebaseSocial.html │ ├── FirebaseUI.html │ ├── RealtimeDatabase.html │ ├── Rplot001.png │ ├── Storage.html │ ├── check_installed.html │ ├── check_providers.html │ ├── check_urls.html │ ├── config.html │ ├── create_unique_id.html │ ├── dependencies.html │ ├── encryption.html │ ├── figures │ │ └── logo.png │ ├── get_config_from_env.html │ ├── get_config_from_file.html │ ├── index.html │ ├── pkg_file.html │ ├── read_config.html │ ├── recaptcha.html │ ├── reqSignin.html │ └── reqSignout.html └── sitemap.xml ├── inst ├── app │ └── app.R └── packer │ ├── analytics.js │ ├── analytics.js.LICENSE.txt │ ├── auth.js │ ├── auth.js.LICENSE.txt │ ├── core.js │ ├── core.js.LICENSE.txt │ ├── email-link.js │ ├── email-password.js │ ├── firebaseui.js.LICENSE.txt │ ├── oauth.js │ ├── phone.js │ ├── real-time.js │ ├── real-time.js.LICENSE.txt │ ├── runtime.js │ ├── social.js │ ├── storage.js │ ├── storage.js.LICENSE.txt │ ├── ui.js │ ├── ui.js.LICENSE.txt │ └── utilities.js ├── makefile ├── man ├── Analytics.Rd ├── Firebase.Rd ├── FirebaseAuth.Rd ├── FirebaseEmailLink.Rd ├── FirebaseEmailPassword.Rd ├── FirebaseOauthProviders.Rd ├── FirebasePhone.Rd ├── FirebaseSocial.Rd ├── FirebaseUI.Rd ├── RealtimeDatabase.Rd ├── Storage.Rd ├── check_installed.Rd ├── check_providers.Rd ├── check_urls.Rd ├── config.Rd ├── create_unique_id.Rd ├── dependencies.Rd ├── encryption.Rd ├── figures │ └── logo.png ├── get_config_from_env.Rd ├── get_config_from_file.Rd ├── pkg_file.Rd ├── read_config.Rd ├── recaptcha.Rd ├── reqSignin.Rd └── reqSignout.Rd ├── mkdocs.yml ├── package-lock.json ├── package.json ├── pkgdown └── favicon │ ├── apple-touch-icon-120x120.png │ ├── apple-touch-icon-152x152.png │ ├── apple-touch-icon-180x180.png │ ├── apple-touch-icon-60x60.png │ ├── apple-touch-icon-76x76.png │ ├── apple-touch-icon.png │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ └── favicon.ico ├── site ├── 404.html ├── CODE_OF_CONDUCT.html ├── LICENSE.html ├── SECURITY.html ├── apple-touch-icon-120x120.png ├── apple-touch-icon-152x152.png ├── apple-touch-icon-180x180.png ├── apple-touch-icon-60x60.png ├── apple-touch-icon-76x76.png ├── apple-touch-icon.png ├── articles │ ├── analytics.html │ ├── demo.html │ ├── email-link.html │ ├── email-password.html │ ├── firebase_email_password.gif │ ├── firebase_redirect.png │ ├── firebase_yahoo.png │ ├── fireblaze_github.png │ ├── fireblaze_github_popup.png │ ├── fireblaze_google.png │ ├── fireblaze_home.png │ ├── fireblaze_project.png │ ├── fireblaze_signin_method.png │ ├── fireblaze_social.gif │ ├── fireblaze_step_1.png │ ├── fireblaze_step_2.png │ ├── fireblaze_users.png │ ├── fireblazer_project_setup1.png │ ├── flow.html │ ├── get-started.html │ ├── github_oauth.png │ ├── index.html │ ├── manage.html │ ├── oauth-providers.html │ ├── phone.html │ ├── social.html │ ├── state-persistence.html │ ├── storage.html │ ├── ui.html │ └── ui_simple.png ├── assets │ ├── images │ │ └── favicon.png │ ├── javascripts │ │ ├── bundle.b425cdc4.min.js │ │ ├── bundle.b425cdc4.min.js.map │ │ ├── lunr │ │ │ ├── min │ │ │ │ ├── lunr.ar.min.js │ │ │ │ ├── lunr.da.min.js │ │ │ │ ├── lunr.de.min.js │ │ │ │ ├── lunr.du.min.js │ │ │ │ ├── lunr.es.min.js │ │ │ │ ├── lunr.fi.min.js │ │ │ │ ├── lunr.fr.min.js │ │ │ │ ├── lunr.hi.min.js │ │ │ │ ├── lunr.hu.min.js │ │ │ │ ├── lunr.hy.min.js │ │ │ │ ├── lunr.it.min.js │ │ │ │ ├── lunr.ja.min.js │ │ │ │ ├── lunr.jp.min.js │ │ │ │ ├── lunr.kn.min.js │ │ │ │ ├── lunr.ko.min.js │ │ │ │ ├── lunr.multi.min.js │ │ │ │ ├── lunr.nl.min.js │ │ │ │ ├── lunr.no.min.js │ │ │ │ ├── lunr.pt.min.js │ │ │ │ ├── lunr.ro.min.js │ │ │ │ ├── lunr.ru.min.js │ │ │ │ ├── lunr.sa.min.js │ │ │ │ ├── lunr.stemmer.support.min.js │ │ │ │ ├── lunr.sv.min.js │ │ │ │ ├── lunr.ta.min.js │ │ │ │ ├── lunr.te.min.js │ │ │ │ ├── lunr.th.min.js │ │ │ │ ├── lunr.tr.min.js │ │ │ │ ├── lunr.vi.min.js │ │ │ │ └── lunr.zh.min.js │ │ │ ├── tinyseg.js │ │ │ └── wordcut.js │ │ └── workers │ │ │ ├── search.208ed371.min.js │ │ │ └── search.208ed371.min.js.map │ └── stylesheets │ │ ├── main.26e3688c.min.css │ │ ├── main.26e3688c.min.css.map │ │ ├── palette.ecc896b0.min.css │ │ └── palette.ecc896b0.min.css.map ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── docsearch.css ├── docsearch.js ├── favicon-16x16.png ├── favicon-32x32.png ├── favicon.ico ├── index.html ├── link.svg ├── logo.png ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── Analytics.html │ ├── Firebase.html │ ├── FirebaseAuth.html │ ├── FirebaseEmailLink.html │ ├── FirebaseEmailPassword.html │ ├── FirebaseOauthProviders.html │ ├── FirebasePhone.html │ ├── FirebaseSocial.html │ ├── FirebaseUI.html │ ├── RealtimeDatabase.html │ ├── Rplot001.png │ ├── Storage.html │ ├── check_installed.html │ ├── check_providers.html │ ├── check_urls.html │ ├── config.html │ ├── create_unique_id.html │ ├── dependencies.html │ ├── encryption.html │ ├── figures │ │ └── logo.png │ ├── get_config_from_env.html │ ├── get_config_from_file.html │ ├── index.html │ ├── pkg_file.html │ ├── read_config.html │ ├── recaptcha.html │ ├── reqSignin.html │ └── reqSignout.html ├── search │ └── search_index.json ├── sitemap.xml └── sitemap.xml.gz ├── srcjs ├── components │ ├── analytics.js │ ├── email-link.js │ ├── email-password.js │ ├── oauth.js │ ├── phone.js │ ├── real-time.js │ ├── social.js │ └── storage.js ├── config │ ├── entry_points.json │ ├── externals.json │ ├── loaders.json │ ├── misc.json │ └── output_path.json ├── core.js ├── style.css ├── ui.js └── utils.js ├── vignettes ├── .gitignore ├── analytics.Rmd ├── demo.Rmd ├── email-link.Rmd ├── email-password.Rmd ├── firebase_email_password.gif ├── firebase_redirect.png ├── firebase_yahoo.png ├── fireblaze_facebook.png ├── fireblaze_github.png ├── fireblaze_github_popup.png ├── fireblaze_google.png ├── fireblaze_home.png ├── fireblaze_project.png ├── fireblaze_signin_method.png ├── fireblaze_social.gif ├── fireblaze_step_1.png ├── fireblaze_step_2.png ├── fireblaze_users.png ├── fireblazer_project_setup1.png ├── fireblazer_step_3.png ├── flow.Rmd ├── get-started.Rmd ├── github_oauth.png ├── manage.Rmd ├── oauth-providers.Rmd ├── phone.Rmd ├── social.Rmd ├── state-persistence.Rmd ├── storage.Rmd ├── ui.Rmd ├── ui_simple.png └── yahoo_create.png ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^LICENSE\.md$ 2 | ^dev$ 3 | ^\.travis\.yml$ 4 | ^\.circleci$ 5 | ^\.circleci/config\.yml$ 6 | ^appveyor\.yml$ 7 | ^\.github$ 8 | ^_pkgdown\.yml$ 9 | ^docs$ 10 | ^pkgdown$ 11 | ^vignettes$ 12 | ^index\.md$ 13 | ^CODE_OF_CONDUCT\.md$ 14 | firebase.rds 15 | ^cran-comments\.md$ 16 | ^CRAN-RELEASE$ 17 | ^srcjs$ 18 | test.R 19 | ^SECURITY\.md$ 20 | ^node_modules$ 21 | ^package\.json$ 22 | ^package-lock\.json$ 23 | ^webpack\.dev\.js$ 24 | ^webpack\.prod\.js$ 25 | ^webpack\.common\.js$ 26 | ^makefile$ 27 | ^mkdocs\.yml$ 28 | ^site$ 29 | ^CRAN-SUBMISSION$ 30 | ^\.gitattributes$ 31 | ^\.vscode$ 32 | -------------------------------------------------------------------------------- /.Rprofile: -------------------------------------------------------------------------------- 1 | if(requireNamespace('packer', quietly = TRUE)){ 2 | packer::engine_adapt() 3 | } else { 4 | warning("This package requires packer: `install.packages('packer')`") 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.html linguist-vendored -------------------------------------------------------------------------------- /.github/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/security-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Security Issue 3 | about: This is a security issue 4 | title: '' 5 | labels: '' 6 | assignees: JohnCoene 7 | 8 | --- 9 | 10 | Do not post it here please. 11 | 12 | Posting a security issue on Github only makes more people aware of the vulnerability. 13 | 14 | Instead, contact me via a personal message on [twitter](https://twitter.com/jdatap) or email (jcoenep [at] gmail). 15 | 16 | Thank you 17 | -------------------------------------------------------------------------------- /.github/workflows/R-CMD-check.yaml: -------------------------------------------------------------------------------- 1 | # For help debugging build failures open an issue on the RStudio community with the 'github-actions' tag. 2 | # https://community.rstudio.com/new-topic?category=Package%20development&tags=github-actions 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - master 8 | pull_request: 9 | branches: 10 | - main 11 | - master 12 | 13 | name: R-CMD-check 14 | 15 | jobs: 16 | R-CMD-check: 17 | runs-on: ${{ matrix.config.os }} 18 | 19 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 20 | 21 | strategy: 22 | fail-fast: false 23 | matrix: 24 | config: 25 | - {os: windows-latest, r: 'release'} 26 | - {os: macOS-latest, r: 'release'} 27 | - {os: ubuntu-20.04, r: 'release', rspm: "https://packagemanager.rstudio.com/cran/__linux__/focal/latest"} 28 | 29 | env: 30 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 31 | RSPM: ${{ matrix.config.rspm }} 32 | 33 | steps: 34 | - uses: actions/checkout@v3 35 | 36 | - uses: r-lib/actions/setup-r@v2 37 | with: 38 | r-version: ${{ matrix.config.r }} 39 | 40 | - uses: r-lib/actions/setup-pandoc@v2 41 | 42 | - name: Cache R packages 43 | if: runner.os != 'Windows' 44 | uses: actions/cache@v3 45 | with: 46 | path: ${{ env.R_LIBS_USER }} 47 | key: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1-${{ hashFiles('.github/depends.Rds') }} 48 | restore-keys: ${{ runner.os }}-${{ hashFiles('.github/R-version') }}-1- 49 | 50 | - name: Install system dependencies 51 | if: runner.os == 'Linux' 52 | run: | 53 | sudo apt-get install -y libcurl4-openssl-dev 54 | while read -r cmd 55 | do 56 | eval sudo $cmd 57 | done < <(Rscript -e 'writeLines(remotes::system_requirements("ubuntu", "20.04"))') 58 | 59 | - name: Install dependencies 60 | run: | 61 | r = getOption("repos") 62 | r["CRAN"] = "http://cran.us.r-project.org" 63 | options(repos = r) 64 | install.packages("remotes", repos = "http://cran.us.r-project.org") 65 | remotes::install_deps(dependencies = TRUE) 66 | remotes::install_cran("rcmdcheck") 67 | shell: Rscript {0} 68 | 69 | - name: Check 70 | env: 71 | _R_CHECK_CRAN_INCOMING_REMOTE_: false 72 | run: rcmdcheck::rcmdcheck(args = c("--no-manual", "--as-cran"), error_on = "error", check_dir = "check") 73 | shell: Rscript {0} 74 | 75 | - name: Upload check results 76 | if: failure() 77 | uses: actions/upload-artifact@main 78 | with: 79 | name: ${{ runner.os }}-r${{ matrix.config.r }}-results 80 | path: check 81 | 82 | -------------------------------------------------------------------------------- /.github/workflows/packer-check.yml: -------------------------------------------------------------------------------- 1 | name: packer 2 | 3 | on: 4 | push: 5 | branches: 6 | - DEV 7 | 8 | jobs: 9 | check: 10 | 11 | env: 12 | R_REMOTES_NO_ERRORS_FROM_WARNINGS: true 13 | 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v2 18 | 19 | - uses: r-lib/actions/setup-pandoc@v1 20 | 21 | - uses: r-lib/actions/setup-r@v1 22 | with: 23 | r-version: ${{ matrix.config.r }} 24 | http-user-agent: ${{ matrix.config.http-user-agent }} 25 | use-public-rspm: true 26 | 27 | - uses: r-lib/actions/setup-r-dependencies@v1 28 | with: 29 | extra-packages: packer 30 | 31 | - name: Check minification 32 | run: Rscript -e "packer:::are_minified('inst/packer')" 33 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | firebase.rds 2 | dev 3 | inst/doc 4 | test.R 5 | node_modules 6 | .Renviron 7 | .vscode 8 | .Rhistory -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # R for travis: see documentation at https://docs.travis-ci.com/user/languages/r 2 | 3 | language: R 4 | cache: packages 5 | -------------------------------------------------------------------------------- /CRAN-SUBMISSION: -------------------------------------------------------------------------------- 1 | Version: 1.0.2 2 | Date: 2023-07-07 08:37:17 UTC 3 | SHA: c520d3c8fb1351cf0f5b508e2b01f771b7bd755b 4 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: firebase 2 | Title: Integrates 'Google Firebase' Authentication Storage, and 'Analytics' with 'Shiny' 3 | Version: 1.0.2 4 | Date: 2023-07-07 5 | Authors@R: c( 6 | person( 7 | given = "John", 8 | family = "Coene", 9 | role = c("aut", "cph"), 10 | email = "jcoenep@gmail.com" 11 | ), 12 | person( 13 | given = "David", 14 | family ="Munoz Tord", 15 | email = "david.munoztord@mailbox.org", 16 | role = c("cre", "ctb"), 17 | comment = c(ORCID = "0000-0001-7954-8295")), 18 | person( 19 | given = "Juha", 20 | family = "Itkonen", 21 | role = "ctb" 22 | )) 23 | Description: Authenticate users in 'Shiny' applications using 'Google Firebase' 24 | with any of the many methods provided; email and password, email link, or 25 | using a third-party provider such as 'Github', 'Twitter', or 'Google'. 26 | Use 'Firebase Storage' to store files securely, and leverage 'Firebase Analytics' 27 | to easily log events and better understand your audience. 28 | License: GPL (>= 3) 29 | Encoding: UTF-8 30 | LazyData: false 31 | Roxygen: list(markdown = TRUE) 32 | Imports: 33 | cli, 34 | jose, 35 | shiny, 36 | openssl, 37 | jsonlite, 38 | base64enc, 39 | htmltools 40 | Suggests: 41 | R6 (>= 2.5.0) 42 | RoxygenNote: 7.2.3 43 | URL: https://firebase.john-coene.com/, https://github.com/JohnCoene/firebase 44 | BugReports: https://github.com/JohnCoene/firebase/issues 45 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(Analytics) 4 | export(Firebase) 5 | export(FirebaseAuth) 6 | export(FirebaseEmailLink) 7 | export(FirebaseEmailPassword) 8 | export(FirebaseOauthProviders) 9 | export(FirebasePhone) 10 | export(FirebaseSocial) 11 | export(FirebaseUI) 12 | export(RealtimeDatabase) 13 | export(Storage) 14 | export(firebaseUIContainer) 15 | export(firebase_config) 16 | export(recaptchaUI) 17 | export(reqSignin) 18 | export(reqSignout) 19 | export(useFirebase) 20 | export(useFirebaseUI) 21 | importFrom(base64enc,base64encode) 22 | importFrom(cli,cli_alert_danger) 23 | importFrom(cli,cli_alert_info) 24 | importFrom(cli,cli_alert_success) 25 | importFrom(cli,cli_alert_warning) 26 | importFrom(cli,cli_rule) 27 | importFrom(htmltools,htmlDependency) 28 | importFrom(jose,jwt_decode_sig) 29 | importFrom(jsonlite,fromJSON) 30 | importFrom(openssl,read_cert) 31 | importFrom(shiny,div) 32 | importFrom(shiny,req) 33 | importFrom(shiny,singleton) 34 | importFrom(shiny,tagAppendAttributes) 35 | importFrom(shiny,tagList) 36 | importFrom(shiny,tags) 37 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # firebase 1.0.2 2 | 3 | - Update firebase to `9.6.7` to fix 4 | [#23](https://github.com/JohnCoene/firebase/issues/23) 5 | - Allow passing parameters to OAuth providers fixes [#33](https://github.com/JohnCoene/firebase/issues/33) 6 | - Fix instructions to setup Microsoft 7 | - Resubmit to CRAN 8 | 9 | # firebase 1.0.1 10 | 11 | - Ressource dependencies registered on attach. 12 | - Fix issue where classes were not correctly exported. 13 | 14 | # firebase 1.0.0 15 | 16 | - Add support for phone sign in. 17 | - Remove deprecated `create_config` function, use 18 | `firebase_config`. 19 | - Fix issue with persistence 20 | [#14](https://github.com/JohnCoene/firebase/issues/14) 21 | - Upgrade firebase.js to modular, tree-shakable version 9 (latest) 22 | - Use [packer](https://packer.john-coene.com/) to bundle with 23 | webpack for better performances and load time. 24 | - Clean up core class, deprecating several (genuinely) useless 25 | methods. 26 | - Deprecate `useFirebaseUI` in favour of `firebaseUIContainer`. 27 | - In `useFirebase` deprecate `analytics` and `firestore` arguments. 28 | - **Breaking** `FirebaseEmailLink` the method called `send` has been 29 | renamed to `send_email`: this method was overwriting an internal 30 | private method, actually breaking many things. 31 | - Added `Storage` class to use 32 | [Firebase Storage](https://firebase.google.com/docs/storage), 33 | requires the user to be signed in. 34 | - Added `Analytics` class to use 35 | [Firebase Analytics](https://firebase.google.com/docs/analytics) 36 | - Add ability to use environment variables instead of the firebase 37 | config file 38 | [#15](https://github.com/JohnCoene/firebase/issues/15) 39 | - New documentation site 40 | - `FirebaseEmailLink` the `config` method is no longer compulsary; 41 | redirect URL is dynamically fetched. 42 | - Fix [#17](https://github.com/JohnCoene/firebase/issues/17) 43 | remove babel breaks polyfill. 44 | - Modular approach implemented: dependencies are rendered 45 | client-side only where needed. 46 | 47 | # firebase 0.2.1 48 | 49 | - Allow firebase to work in modules. 50 | - Added `email_link` to `FirebaseUI`. 51 | - Added `request_token_id` and `get_id_token` methods 52 | to retrieve the user's id token. 53 | - Update firebase and friends to v8.1 54 | 55 | # firebase 0.2.0 56 | 57 | - Fix potential security issue [#11](https://github.com/JohnCoene/firebase/issues/11) 58 | - Add logging in many places to make it easier to debug 59 | 60 | # firebase 0.1.1 61 | 62 | - Deprecate the function `create_config` in favour of 63 | `firebase_config` 64 | 65 | # firebase 0.1.0 66 | 67 | First CRAN submission. All `get_` methods return a list of length 2 containing `success` a boolean indicating whether to operation was successful and `response` containing the result of the response if there is one, otherwise the string `successful`, or the `error` if there is one. 68 | 69 | # firebase 0.0.1.9000 70 | 71 | Initial version 72 | -------------------------------------------------------------------------------- /R/class-analytics.R: -------------------------------------------------------------------------------- 1 | #' Analytics 2 | #' 3 | #' @return An object of class \code{Analytics}. 4 | #' 5 | #' @export 6 | Analytics <- R6::R6Class( 7 | "Analytics", 8 | inherit = Firebase, 9 | public = list( 10 | #' @details Initialise 11 | #' 12 | #' Initialise an analytics object. 13 | #' 14 | #' @param enable Whether to internally enable analytics 15 | #' see `launch` method. 16 | initialize = function(enable = TRUE){ 17 | super$initialize() 18 | super$.render_deps( 19 | list(firebase_dep_analytics()) 20 | ) 21 | private$.enabled <- FALSE 22 | }, 23 | #' @details Launch 24 | #' 25 | #' Launch the analytics tracking. 26 | #' Note that analytics is not launched by the 27 | #' constructor in order to be able to enable 28 | #' or disable the tracking prior to the launch. 29 | #' This is because once Google Analytics is 30 | #' launched it cannot be disabled. If needed 31 | #' ask the user before running this method. 32 | #' The enabling and disabling of tracking provided 33 | #' by the package is only internal, e.g.: disabling 34 | #' tracking during a session will stop the `log_event` 35 | #' method from registering event but default Google 36 | #' Analytics will still be running. 37 | launch = function() { 38 | if(!private$.enabled) 39 | return(self) 40 | 41 | super$.send("initialize-analytics") 42 | }, 43 | #' @details Enable Tracking 44 | #' Internally enables tracking. 45 | enable = function(){ 46 | private$.enabled <- TRUE 47 | }, 48 | #' @details Disable Tracking 49 | #' Internally disables tracking: running methods 50 | #' from this instance of the class will not actually 51 | #' register with Google Analytics. 52 | disable = function() { 53 | private$.enabled <- FALSE 54 | }, 55 | #' @details Log Event 56 | #' 57 | #' Log an event. 58 | #' 59 | #' @param event Event to log choose from 60 | #' [this list](https://firebase.google.com/docs/analytics/events?platform=web) 61 | #' of supported events. 62 | #' @param params Event parameters. 63 | log_event = function(event, params = NULL) { 64 | if(!private$.enabled) 65 | return(self) 66 | 67 | if(missing(event)) 68 | stop("Missing `event`") 69 | 70 | super$.send( 71 | "log-event", 72 | event = event, 73 | params = params 74 | ) 75 | 76 | invisible(self) 77 | }, 78 | #' @details Set user properties 79 | #' 80 | #' @param ... Named arguments defining the properties of the user. 81 | set_user_properties = function(...){ 82 | if(!private$.enabled) 83 | return(self) 84 | 85 | props <- list(...) 86 | if(!length(props)) 87 | stop("Must pass named properties") 88 | 89 | nms <- names(props) 90 | if("" %in% nms) 91 | stop("Must pass named options") 92 | 93 | if(c("Age", "Gender", "Interest") %in% nms) 94 | stop("Cannot use `Age`, `Gender`, or `Interest` properties, they are reserved") 95 | 96 | super$.send( 97 | "set-user-properties", 98 | props = as.list(props) 99 | ) 100 | 101 | invisible(self) 102 | } 103 | ), 104 | private = list( 105 | .enabled = TRUE 106 | ) 107 | ) -------------------------------------------------------------------------------- /R/class-core.R: -------------------------------------------------------------------------------- 1 | #' Firebase 2 | #' 3 | #' Core Firebase class. 4 | #' 5 | #' @return An object of class \code{Firebase}. 6 | #' 7 | #' @field session A valid Shiny session. 8 | #' 9 | #' @export 10 | Firebase <- R6::R6Class( 11 | "Firebase", 12 | public = list( 13 | session = NULL, 14 | #' @details Initialise Firebase 15 | #' 16 | #' Initialises the Firebase application client-side. 17 | #' 18 | #' @param config_path Path to the configuration file as created by \code{\link{firebase_config}}. 19 | #' @param session A valid shiny session. 20 | #' 21 | #' @return Invisibly return the class. 22 | initialize = function( 23 | config_path = "firebase.rds", 24 | session = shiny::getDefaultReactiveDomain() 25 | ){ 26 | 27 | conf <- read_config(config_path) 28 | self$session <- session 29 | private$.unique_id <- create_unique_id() 30 | private$.conf <- conf 31 | private$.project_id <- conf$projectId 32 | 33 | # namespace 34 | private$.namespace(session) 35 | private$.send( 36 | "initialize-core", 37 | conf = conf 38 | ) 39 | }, 40 | #' @details Expose App 41 | #' 42 | #' Expose the `firebaseApp` object product of `initializeApp()` by 43 | #' attaching it to the `window`: access it with `window.firebaseApp`. 44 | expose_app = function() { 45 | private$.send("expose-app") 46 | invisible(self) 47 | }, 48 | #' @details Print the class 49 | print = function(){ 50 | cli_rule("Firebase") 51 | } 52 | ), 53 | private = list( 54 | send = function(func, msg = list()){ 55 | func <- paste0("fireblaze-", func) 56 | msg$ns <- private$.ns 57 | self$session$sendCustomMessage(func, msg) 58 | }, 59 | .send = function(func, ...){ 60 | func <- paste0("fireblaze-", func) 61 | msg <- list( 62 | ns = private$.ns, 63 | ... 64 | ) 65 | self$session$sendCustomMessage(func, msg) 66 | }, 67 | .render_deps = function(deps){ 68 | private$.send("render-dependencies", deps = deps) 69 | }, 70 | get_input = function(name){ 71 | name <- paste0("fireblaze_", name) 72 | self$session[["input"]][[name]] 73 | }, 74 | .namespace = function(session){ 75 | ns <- session$ns(NULL) 76 | if(length(ns) > 0 && ns != "") 77 | ns <- paste0(ns, "-") 78 | 79 | # server - no ns 80 | if(length(ns) == 0L) 81 | ns <- "" 82 | 83 | private$.ns <- ns 84 | }, 85 | get_project_id = function() { 86 | return(invisible(private$.project_id)) 87 | }, 88 | .unique_id = NULL, 89 | .ns = "", 90 | .project_id = NULL, 91 | .conf = list() 92 | ) 93 | ) 94 | -------------------------------------------------------------------------------- /R/class-oauth.R: -------------------------------------------------------------------------------- 1 | #' OAuth Providers 2 | #' 3 | #' Use OAuth provides such as Github or Facebook to allow users to conveniently sign in. 4 | #' 5 | #' @return An object of class \code{FirebaseOauthProviders}. 6 | #' 7 | #' @examples 8 | #' library(shiny) 9 | #' library(firebase) 10 | #' 11 | #' ui <- fluidPage( 12 | #' useFirebase(), 13 | #' actionButton("signin", "Sign in with Microsoft", icon = icon("microsoft")), 14 | #' plotOutput("plot") 15 | #' ) 16 | #' 17 | #' server <- function(input, output, session){ 18 | #' f <- FirebaseOauthProviders$ 19 | #' new()$ 20 | #' set_provider("microsoft.com") 21 | #' 22 | #' observeEvent(input$signin, { 23 | #' f$launch() 24 | #' }) 25 | #' 26 | #' output$plot <- renderPlot({ 27 | #' f$req_sign_in() 28 | #' plot(cars) 29 | #' }) 30 | #' 31 | #' } 32 | #' 33 | #' \dontrun{shinyApp(ui, server)} 34 | #' 35 | #' @export 36 | FirebaseOauthProviders <- R6::R6Class( 37 | "FirebaseOauthProviders", 38 | inherit = FirebaseAuth, 39 | public = list( 40 | #' @details Initialiases Firebase Email Link 41 | #' 42 | #' Initialises the Firebase application client-side. 43 | #' 44 | #' @param config_path Path to the configuration file as created by \code{\link{firebase_config}}. 45 | #' @param session A valid shiny session. 46 | #' @param persistence How the auth should persit: \code{none}, the user has to sign in at every visit, 47 | #' \code{session} will only persist in current tab, \code{local} persist even when window is closed. 48 | #' @param language_code Sets the language to use for the UI. 49 | #' Supported languages are listed [here](https://github.com/firebase/firebaseui-web/blob/master/LANGUAGES.md). 50 | #' Set to `browser` to use the default browser language of the user. 51 | initialize = function( 52 | persistence = c("session", "local", "memory"), 53 | config_path = "firebase.rds", 54 | language_code = NULL, 55 | session = shiny::getDefaultReactiveDomain() 56 | ){ 57 | super$initialize( 58 | persistence, 59 | config_path, 60 | language_code, 61 | session 62 | ) 63 | super$.render_deps( 64 | list(firebase_dep_oauth()) 65 | ) 66 | }, 67 | #' @details Define provider to use 68 | #' @param provider The provider to user, e.g.: \code{microsoft.com}, \code{yahoo.com} or \code{google.com}. 69 | #' @param ... Additional options to pass to [setCustomParameters](https://github.com/firebase/snippets-web/blob/69c85abdc7cd6990618720cd33aa0d1ee357c652/snippets/auth-next/microsoft-oauth/auth_msft_provider_params.js#L8-L13). 70 | #' @return self 71 | set_provider = function(provider, ...){ 72 | if(missing(provider)) 73 | stop("Missing provider", call. = FALSE) 74 | 75 | super$send( 76 | "set-oauth-provider", 77 | list( 78 | id = super$.unique_id, 79 | provider = provider, 80 | opts = list(...) 81 | ) 82 | ) 83 | 84 | private$.provider <- provider 85 | invisible(self) 86 | }, 87 | #' @details Launch sign in with Google. 88 | #' @param flow Authentication flow, either popup or redirect. 89 | #' @param get_credentials Whether to extract underlying oauth credentials. 90 | #' @return self 91 | launch = function(flow = c("popup", "redirect"), get_credentials = FALSE){ 92 | private$launch_oauth(match.arg(flow), get_credentials = get_credentials) 93 | invisible(self) 94 | } 95 | ), 96 | private = list( 97 | .provider = NULL, 98 | launch_oauth = function(flow = c("popup", "redirect"), get_credentials = FALSE){ 99 | call <- paste0("oauth-sign-in-", flow) 100 | super$send(call, list(id = super$.unique_id, credentials = get_credentials)) 101 | } 102 | ) 103 | ) 104 | -------------------------------------------------------------------------------- /R/class-phone.R: -------------------------------------------------------------------------------- 1 | #' Phone 2 | #' 3 | #' Use mobile phone numbers to authenticate users. 4 | #' 5 | #' @return An object of class \code{FirebasePhone}. 6 | #' 7 | #' @export 8 | FirebasePhone <- R6::R6Class( 9 | "FirebasePhone", 10 | inherit = FirebaseAuth, 11 | public = list( 12 | #' @details Initialiases Firebase Phone 13 | #' 14 | #' Initialises the Firebase application client-side. 15 | #' 16 | #' @param config_path Path to the configuration file as created by \code{\link{firebase_config}}. 17 | #' @param session A valid shiny session. 18 | #' @param persistence How the auth should persit: \code{none}, the user has to sign in at every visit, 19 | #' \code{session} will only persist in current tab, \code{local} persist even when window is closed. 20 | #' @param language_code Sets the language to use for the UI. 21 | #' Supported languages are listed [here](https://github.com/firebase/firebaseui-web/blob/master/LANGUAGES.md). 22 | #' Set to `browser` to use the default browser language of the user. 23 | initialize = function( 24 | persistence = c("session", "local", "memory"), 25 | config_path = "firebase.rds", 26 | language_code = NULL, 27 | session = shiny::getDefaultReactiveDomain() 28 | ){ 29 | super$initialize( 30 | persistence, 31 | config_path, 32 | language_code, 33 | session 34 | ) 35 | super$.render_deps( 36 | list(firebase_dep_phone()) 37 | ) 38 | }, 39 | #' @details Verify a phhone number 40 | #' @param number Phone number of the user. 41 | #' @param id Id of the button that triggers verification. 42 | #' If this is `NULL` the user has to go through the recaptcha, 43 | #' if not `NULL` is invisible. 44 | verify = function(number, id = NULL) { 45 | if(missing(number)) 46 | stop("Missing `number`") 47 | 48 | id <- ifelse(is.null(id), "firebase-recaptcha", id) 49 | 50 | super$.send( 51 | "phone-verify", 52 | id = id, 53 | number = number 54 | ) 55 | }, 56 | #' @details Results from the recaptcha 57 | get_recaptcha = function(){ 58 | super$get_input("phone_recaptcha") 59 | }, 60 | #' @details Confirm a code 61 | #' @param code Confirmation code received by the user. 62 | confirm = function(code) { 63 | if(missing(code)) 64 | stop("Missing `code`") 65 | 66 | super$send( 67 | "phone-confirm", 68 | list( 69 | code = code 70 | ) 71 | ) 72 | 73 | invisible(self) 74 | }, 75 | #' @details Get Verification 76 | #' @return A list with a boolean (`success`) indicating 77 | #' whether the operation was successful and a `response` 78 | #' contianing the response from Firebase. 79 | get_verification = function(){ 80 | super$get_input("phone_verification") 81 | }, 82 | #' @details Get Confirmation 83 | #' @return A list with a boolean (`success`) indicating 84 | #' whether the operation was successful and a `response` 85 | #' contianing the response from Firebase. 86 | get_confirmation = function(){ 87 | super$get_input("phone_confirmation") 88 | } 89 | ) 90 | ) 91 | 92 | #' Recaptcha 93 | #' 94 | #' Add the recaptcha, require for the `FirebasePhone` 95 | #' class. 96 | #' 97 | #' @param ns Namespace, optional, only required if using 98 | #' this function in multiple places. 99 | #' 100 | #' @name recaptcha 101 | #' @export 102 | recaptchaUI <- function(ns = function(x) {x}){ 103 | div( 104 | id = ns("firebase-recaptcha") 105 | ) 106 | } 107 | -------------------------------------------------------------------------------- /R/class-social.R: -------------------------------------------------------------------------------- 1 | #' Social 2 | #' 3 | #' Use social sites for authentication. 4 | #' 5 | #' @return An object of class \code{FirebaseSocial}. 6 | #' 7 | #' @examples 8 | #' library(shiny) 9 | #' library(firebase) 10 | #' 11 | #' # define signin 12 | #' signin <- modalDialog( 13 | #' title = "Login", 14 | #' actionButton("google", "Google", icon = icon("google"), class = "btn-danger"), 15 | #' actionButton("github", "Github", icon = icon("github")), 16 | #' footer = NULL 17 | #' ) 18 | #' 19 | #' ui <- fluidPage( 20 | #' useFirebase() 21 | #' ) 22 | #' 23 | #' server <- function(input, output) { 24 | #' showModal(signin) 25 | #' 26 | #' f <- FirebaseSocial$new() 27 | #' 28 | #' observeEvent(input$google, { 29 | #' f$launch_google() 30 | #' }) 31 | #' 32 | #' observeEvent(input$github, { 33 | #' f$launch_github() 34 | #' }) 35 | #' } 36 | #' 37 | #' \dontrun{shinyApp(ui, server)} 38 | #' 39 | #' @export 40 | FirebaseSocial <- R6::R6Class( 41 | "FirebaseSocial", 42 | inherit = FirebaseAuth, 43 | public = list( 44 | #' @details Initialiases Firebase Social 45 | #' 46 | #' Initialises the Firebase application client-side. 47 | #' 48 | #' @param config_path Path to the configuration file as created by \code{\link{firebase_config}}. 49 | #' @param session A valid shiny session. 50 | #' @param persistence How the auth should persit: \code{none}, the user has to sign in at every visit, 51 | #' \code{session} will only persist in current tab, \code{local} persist even when window is closed. 52 | #' @param language_code Sets the language to use for the UI. 53 | #' Supported languages are listed [here](https://github.com/firebase/firebaseui-web/blob/master/LANGUAGES.md). 54 | #' Set to `browser` to use the default browser language of the user. 55 | initialize = function( 56 | persistence = c("session", "local", "memory"), 57 | config_path = "firebase.rds", 58 | language_code = NULL, 59 | session = shiny::getDefaultReactiveDomain() 60 | ){ 61 | super$initialize( 62 | persistence, 63 | config_path, 64 | language_code, 65 | session 66 | ) 67 | super$.render_deps( 68 | list(firebase_dep_social()) 69 | ) 70 | }, 71 | #' @details Define the scope to request from Google. 72 | #' @param scope Google scope. 73 | #' @return self 74 | set_scope = function(scope){ 75 | if(missing(scope)) stop("Missing scope", call. = FALSE) 76 | super$send("google-scope", as.list(scope)) 77 | invisible(self) 78 | }, 79 | #' @details Launch sign in with Google. 80 | #' @param flow Authentication flow, either popup or redirect. 81 | #' @return self 82 | launch_google = function(flow = c("popup", "redirect")){ 83 | private$launch_social("google", match.arg(flow)) 84 | invisible(self) 85 | }, 86 | #' @details Launch sign in with Github. 87 | #' @param flow Authentication flow, either popup or redirect. 88 | #' @return self 89 | launch_github = function(flow = c("popup", "redirect")){ 90 | private$launch_social("github", match.arg(flow)) 91 | invisible(self) 92 | }, 93 | #' @details Launch sign in with Facebook. 94 | #' @param flow Authentication flow, either popup or redirect. 95 | #' @return self 96 | launch_facebook = function(flow = c("popup", "redirect")){ 97 | private$launch_social("facebook", match.arg(flow)) 98 | invisible(self) 99 | }, 100 | #' @details Launch sign in with Facebook. 101 | #' @param flow Authentication flow, either popup or redirect. 102 | #' @return self 103 | launch_twitter = function(flow = c("popup", "redirect")){ 104 | private$launch_social("twitter", match.arg(flow)) 105 | invisible(self) 106 | } 107 | ), 108 | private = list( 109 | launch_social = function(social, flow = c("popup", "redirect")){ 110 | call <- paste0(social, "-sign-in-", flow) 111 | super$send(call, list()) 112 | } 113 | ) 114 | ) 115 | -------------------------------------------------------------------------------- /R/toggle.R: -------------------------------------------------------------------------------- 1 | #' Requires Signin 2 | #' 3 | #' Define UI element that require the user to be signed in. This 4 | #' will hide them \emph{viusally} until the user signs in. 5 | #' Note that this is not secure as someone can easily change the 6 | #' CSS when visiting the page to reveal those elements. 7 | #' 8 | #' 9 | #' @return No return value, called for side effects. 10 | #' 11 | #' 12 | #' @param ... Any valid \link[shiny]{tags}. 13 | #' 14 | #' @seealso \code{\link{reqSignout}} 15 | #' 16 | #' @importFrom shiny tagAppendAttributes 17 | #' 18 | #' @export 19 | reqSignin <- function(...) { 20 | tags <- list(...) 21 | 22 | warning("`reqSignin` is not secure, see documentation", call. = FALSE) 23 | 24 | if (length(tags) == 1 && inherits(tags[[1]], "shiny.tag")) { 25 | tags[[1]] <- 26 | tagAppendAttributes( 27 | tags[[1]], 28 | class = "fireblaze__requires__signin fireblaze__hidden" 29 | ) 30 | return( tags[[1]] ) 31 | } else if (length(tags) == 1 && is.list(tags[[1]])) { 32 | return( lapply(tags[[1]], reqSignin) ) 33 | } else if (length(tags) > 1) { 34 | return( lapply(tags, reqSignin) ) 35 | } else { 36 | stop("Invalid shiny tags", call. = FALSE) 37 | } 38 | } 39 | 40 | #' Requires Signout 41 | #' 42 | #' Define UI element that requires \emph{no} user to be signed in. This 43 | #' will hide them \emph{viusally} if no user is signed in. 44 | #' Note that this is not secure as someone can easily change the 45 | #' CSS when visiting the page to reveal those elements. 46 | #' 47 | #' @param ... Any valid \link[shiny]{tags}. 48 | #' 49 | #' @seealso \code{\link{reqSignin}} 50 | #' 51 | #' @importFrom shiny tagAppendAttributes 52 | #' 53 | #' @export 54 | reqSignout <- function(...) { 55 | tags <- list(...) 56 | 57 | warning("`reqSignin` is not secure, see documentation", call. = FALSE) 58 | 59 | if (length(tags) == 1 && inherits(tags[[1]], "shiny.tag")) { 60 | tags[[1]] <- 61 | tagAppendAttributes( 62 | tags[[1]], 63 | class = "fireblaze__requires__signout fireblaze__hidden" 64 | ) 65 | return( tags[[1]] ) 66 | } else if (length(tags) == 1 && is.list(tags[[1]])) { 67 | return( lapply(tags[[1]], reqSignin) ) 68 | } else if (length(tags) > 1) { 69 | return( lapply(tags, reqSignin) ) 70 | } else { 71 | stop("Invalid shiny tags", call. = FALSE) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | #' Get Path 2 | #' 3 | #' Get path to internal file. 4 | #' 5 | #' @return Pkg path. 6 | #' 7 | #' @param path Path to file in \code{inst} directory. 8 | #' 9 | #' @keywords internal 10 | pkg_file <- function(path){ 11 | system.file(path, package = "firebase") 12 | } 13 | 14 | # default config file name 15 | config_file <- "firebase.rds" 16 | 17 | #' Check Providers 18 | #' 19 | #' Check if providers have been set. 20 | #' 21 | #' @param opts Options to check. 22 | #' 23 | #' @keywords internal 24 | check_providers <- function(opts){ 25 | opts <- unlist(opts) 26 | is_set <- sum(opts) 27 | 28 | if(!is_set) 29 | stop("Providers not set, see `set_providers` method.", call. = FALSE) 30 | 31 | invisible() 32 | } 33 | 34 | #' Check URLs 35 | #' 36 | #' Check that tos and privacy policy urls are set. 37 | #' 38 | #' @param fireblaze_ui An object of class \code{\link{FirebaseUI}}. 39 | #' 40 | #' @keywords internal 41 | check_urls <- function(fireblaze_ui){ 42 | # check if still default 43 | if(grepl("^<.*>$", fireblaze_ui$tos_url) || grepl("^<.*>$", fireblaze_ui$privacy_policy_url)) 44 | warning("Missing Terms of Service and/or Privacy policy URL, see `set_tos_url` and `set_privacy_policy_url` methods", call. = FALSE) 45 | 46 | invisible() 47 | } 48 | 49 | #' ID 50 | #' 51 | #' Generates a unique id. 52 | #' 53 | #' @keywords internal 54 | create_unique_id <- function(){ 55 | paste0(sample(c(letters, 1:26), 26), collapse = "") 56 | } 57 | 58 | #' Check that a package installed 59 | #' 60 | #' Checks that a package is installed, throws 61 | #' an error if it is not. 62 | #' 63 | #' @param pkg Package name. 64 | #' 65 | #' @keywords internal 66 | check_installed <- function(pkg) { 67 | if(missing(pkg)) 68 | stop("Missing `pkg`", call. = FALSE) 69 | 70 | if(requireNamespace(pkg, quietly = TRUE)) 71 | return() 72 | 73 | msg <- sprintf("This requires the pacakge: `%s`", pkg) 74 | stop(msg) 75 | } 76 | 77 | encode_file <- function(enc, ext){ 78 | switch( 79 | ext, 80 | "png" = sprintf("data:image/png;base64,%s", enc), 81 | sprintf("data:text/plain;base64,%s", enc) 82 | ) 83 | } 84 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 | 5 | 6 | [Google Firebase](https://firebase.google.com) for shiny, 7 | built with [packer](https://packer.john-coene.com). 8 | 9 | 10 | [![Lifecycle: stable](https://img.shields.io/badge/lifecycle-stable-brightgreen.svg)](https://lifecycle.r-lib.org/articles/stages.html#stable) 11 | ![R-CMD-check](https://github.com/JohnCoene/firebase/workflows/R-CMD-check/badge.svg) 12 | [![packer](https://github.com/JohnCoene/firebase/actions/workflows/packer-check.yml/badge.svg)](https://github.com/JohnCoene/firebase/actions/workflows/packer-check.yml) 13 | 14 | 15 | [Website](https://firebase.john-coene.com) | [Demo](https://shiny.john-coene.com/firebase) | [Get Started](https://firebase.john-coene.com/guide/get-started/) 16 | 17 |
18 | 19 | ## Authentication Methods 20 | 21 | Currently the following methods from Google Firebase are available in the package: 22 | 23 | * Email & Password 24 | * Email Link 25 | * Google 26 | * Github 27 | * Facebook 28 | * Twitter 29 | * Microsoft 30 | * Yahoo! 31 | * Phone 32 | 33 | ## Example 34 | 35 | An application that provides authentication could look like this. 36 | 37 | ```r 38 | library(shiny) 39 | library(firebase) 40 | 41 | ui <- fluidPage( 42 | useFirebase(), # import dependencies, 43 | firebaseUIContainer() 44 | ) 45 | 46 | server <- function(input, output){ 47 | f <- FirebaseUI$ 48 | new()$ # instantiate 49 | set_providers( # define providers 50 | email = TRUE, 51 | google = TRUE 52 | )$ 53 | launch() # launch 54 | } 55 | 56 | shinyApp(ui, server) 57 | ``` 58 | 59 | ## Install 60 | 61 | Install the stable version from CRAN: 62 | 63 | ```r 64 | install.packages("firebase") 65 | ``` 66 | 67 | Install the development from Github using remotes: 68 | 69 | ```r 70 | # install.packages("remotes") 71 | remotes::install_github("JohnCoene/firebase") 72 | ``` 73 | 74 | Get the current bleeding edge refactor with webpack 75 | with [packer](https://packer.john-coene.com) 76 | to improve performances and use firebase JavaScript version 9. 77 | It also includes two new classes `Storage` and `Analytics`. 78 | 79 | ```r 80 | remotes::install_github("JohnCoene/firebase@packer") 81 | ``` 82 | 83 | ## Related 84 | 85 | Below are similar projects: 86 | 87 | - [Polished](https://polished.tech/) 88 | - [SaaS with R by Mark Edmondson](https://github.com/MarkEdmondson1234/Shiny-R-SaaS/) 89 | - [Firebase with R by Andy Merlino](https://github.com/shinyonfire/sof-auth-example) 90 | - [Auth0 with Shiny](https://auth0.com/blog/adding-authentication-to-shiny-server/) 91 | 92 | ## Code of Conduct 93 | 94 | Please note that the firebase project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/0/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. 95 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # SECURITY 2 | 3 | If you spot a security issue or a potential security issue please 4 | do not open an issue. 5 | 6 | Posting a security issue on Github only makes more people aware of the vulnerability. 7 | 8 | Instead, contact me via a personal message on [twitter](https://twitter.com/jdatap) or email (jcoenep [at] gmail). 9 | 10 | Thank you 11 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | # DO NOT CHANGE the "init" and "install" sections below 2 | 3 | # Download script file from GitHub 4 | init: 5 | ps: | 6 | $ErrorActionPreference = "Stop" 7 | Invoke-WebRequest http://raw.github.com/krlmlr/r-appveyor/master/scripts/appveyor-tool.ps1 -OutFile "..\appveyor-tool.ps1" 8 | Import-Module '..\appveyor-tool.ps1' 9 | 10 | install: 11 | ps: Bootstrap 12 | 13 | cache: 14 | - C:\RLibrary 15 | 16 | environment: 17 | NOT_CRAN: true 18 | # env vars that may need to be set, at least temporarily, from time to time 19 | # see https://github.com/krlmlr/r-appveyor#readme for details 20 | # USE_RTOOLS: true 21 | # R_REMOTES_STANDALONE: true 22 | 23 | # Adapt as necessary starting from here 24 | 25 | build_script: 26 | - travis-tool.sh install_deps 27 | 28 | test_script: 29 | - travis-tool.sh run_tests 30 | 31 | on_failure: 32 | - 7z a failure.zip *.Rcheck\* 33 | - appveyor PushArtifact failure.zip 34 | 35 | artifacts: 36 | - path: '*.Rcheck\**\*.log' 37 | name: Logs 38 | 39 | - path: '*.Rcheck\**\*.out' 40 | name: Logs 41 | 42 | - path: '*.Rcheck\**\*.fail' 43 | name: Logs 44 | 45 | - path: '*.Rcheck\**\*.Rout' 46 | name: Logs 47 | 48 | - path: '\*_*.tar.gz' 49 | name: Bits 50 | 51 | - path: '\*_*.zip' 52 | name: Bits 53 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Notes 2 | 3 | 4 | ### Second resubmission (answer to Victoria Wimmer) 5 | 6 | > The Date field is over a month old. 7 | 8 | Sorry indeed a commit reverted it back to last date. Fixed it and rechecked the package on rhub. 9 | 10 | ### First resubmission (answers to Victoria Wimmer) 11 | 12 | > Please proof-read your description text. Currently it reads: "...use 'Firebase Storage' to ..." -> Should probably begin with a capital "U" since it is a new sentence 13 | 14 | Thanks, changed in the DESCRIPTION file. 15 | 16 | 17 | > Please add \value to .Rd files regarding exported methods and explain the functions results in the documentation. Please write about the structure of the output (class) and also what the output means. (If a function does not return a value, please document that too, e.g. \value{No return value, called for side effects} or similar) 18 | Missing Rd-tags in up to 15 .Rd files, e.g.: 19 | Analytics.Rd: \value 20 | dependencies.Rd: \value 21 | Firebase.Rd: \value 22 | FirebaseAuth.Rd: \value 23 | FirebaseEmailLink.Rd: \value 24 | FirebaseEmailPassword.Rd: \value 25 | ... 26 | 27 | 28 | > We added the \value to all the .Rd files regarding exported methods 29 | 30 | 31 | 32 | > Unexecutable code in man/Storage.Rd: 33 | observeEvent(s$get_response() { 34 | 35 | Missing comma indeed ! Fixed it. 36 | 37 | > Functions which are supposed to only run interactively (e.g. shiny) should be wrapped in if(interactive()). 38 | Please replace /dontrun{} with if(interactive()){} if possible, then users can see that the functions are not intended for use in scripts / functions that are supposed to run non interactively. \dontrun{} should only be used if the example really cannot be executed (e.g. because of missing additional software, missing API keys, ...) by the user. That's why wrapping examples in \dontrun{} adds the comment ("# Not run:") as a warning for the user. 39 | 40 | Indeed we wrapped it (and the other ones) in \dontrun{} in purpose because of missing API keys required from Firebase. 41 | 42 | 43 | > Please always make sure to reset to user's options(), working directory or par() after you changed it in examples and vignettes and demos. --> man/FirebaseEmailLink.Rd. e.g.: 44 | old <- options(digits = 3) 45 | ... 46 | options(old) 47 | 48 | Fixed it in FirebaseEmailLink.Rd which was the only example requiring this change. 49 | 50 | 51 | > Additionally: Have the issues why your package was archived been fixed? 52 | 53 | Yes, I talked with the past maintainer and they have been fixed but not resubmitted because of lack of time. 54 | Thanks for your time and feedback ! 55 | 56 | 57 | ## Test environments 58 | - R-hub windows-x86_64-devel (r-devel) 59 | - R-hub ubuntu-gcc-release (r-release) 60 | - R-hub fedora-clang-devel (r-devel) 61 | 62 | ## R CMD check results 63 | 64 | ❯ On windows-x86_64-devel (r-devel) 65 | checking CRAN incoming feasibility ... [16s] NOTE 66 | 67 | New maintainer: 68 | David Munoz Tord 69 | Old maintainer(s): 70 | John Coene 71 | Maintainer: 'David Munoz Tord ' 72 | 73 | ❯ On ubuntu-gcc-release (r-release) 74 | checking CRAN incoming feasibility ... [8s/32s] NOTE 75 | Maintainer: ‘David Munoz Tord ’ 76 | 77 | New maintainer: 78 | David Munoz Tord 79 | Old maintainer(s): 80 | John Coene 81 | 82 | ❯ On ubuntu-gcc-release (r-release), fedora-clang-devel (r-devel) 83 | checking HTML version of manual ... NOTE 84 | Skipping checking HTML validation: no command 'tidy' found 85 | 86 | ❯ On fedora-clang-devel (r-devel) 87 | checking CRAN incoming feasibility ... [12s/39s] NOTE 88 | Maintainer: ‘David Munoz Tord ’ 89 | 90 | New maintainer: 91 | David Munoz Tord 92 | Old maintainer(s): 93 | John Coene 94 | 95 | 0 error ✖ | 0 warnings ✔ | 3 notes ✖ -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /docs/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /docs/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/articles/firebase_email_password.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/firebase_email_password.gif -------------------------------------------------------------------------------- /docs/articles/firebase_redirect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/firebase_redirect.png -------------------------------------------------------------------------------- /docs/articles/firebase_yahoo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/firebase_yahoo.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_github.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_github_popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_github_popup.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_google.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_home.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_project.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_signin_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_signin_method.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_social.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_social.gif -------------------------------------------------------------------------------- /docs/articles/fireblaze_step_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_step_1.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_step_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_step_2.png -------------------------------------------------------------------------------- /docs/articles/fireblaze_users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblaze_users.png -------------------------------------------------------------------------------- /docs/articles/fireblazer_project_setup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/fireblazer_project_setup1.png -------------------------------------------------------------------------------- /docs/articles/github_oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/github_oauth.png -------------------------------------------------------------------------------- /docs/articles/ui_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/articles/ui_simple.png -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/favicon-16x16.png -------------------------------------------------------------------------------- /docs/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/favicon-32x32.png -------------------------------------------------------------------------------- /docs/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/favicon.ico -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/logo.png -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $("div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.1 2 | pkgdown: 2.0.7 3 | pkgdown_sha: ~ 4 | articles: 5 | analytics: analytics.html 6 | demo: demo.html 7 | email-link: email-link.html 8 | email-password: email-password.html 9 | flow: flow.html 10 | get-started: get-started.html 11 | manage: manage.html 12 | oauth-providers: oauth-providers.html 13 | phone: phone.html 14 | social: social.html 15 | state-persistence: state-persistence.html 16 | storage: storage.html 17 | ui: ui.html 18 | last_built: 2023-07-04T12:12Z 19 | 20 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/docs/reference/figures/logo.png -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /404.html 5 | 6 | 7 | /CODE_OF_CONDUCT.html 8 | 9 | 10 | /LICENSE.html 11 | 12 | 13 | /SECURITY.html 14 | 15 | 16 | /articles/analytics.html 17 | 18 | 19 | /articles/demo.html 20 | 21 | 22 | /articles/email-link.html 23 | 24 | 25 | /articles/email-password.html 26 | 27 | 28 | /articles/flow.html 29 | 30 | 31 | /articles/get-started.html 32 | 33 | 34 | /articles/index.html 35 | 36 | 37 | /articles/manage.html 38 | 39 | 40 | /articles/oauth-providers.html 41 | 42 | 43 | /articles/phone.html 44 | 45 | 46 | /articles/social.html 47 | 48 | 49 | /articles/state-persistence.html 50 | 51 | 52 | /articles/storage.html 53 | 54 | 55 | /articles/ui.html 56 | 57 | 58 | /authors.html 59 | 60 | 61 | /index.html 62 | 63 | 64 | /news/index.html 65 | 66 | 67 | /reference/Analytics.html 68 | 69 | 70 | /reference/Firebase.html 71 | 72 | 73 | /reference/FirebaseAuth.html 74 | 75 | 76 | /reference/FirebaseEmailLink.html 77 | 78 | 79 | /reference/FirebaseEmailPassword.html 80 | 81 | 82 | /reference/FirebaseOauthProviders.html 83 | 84 | 85 | /reference/FirebasePhone.html 86 | 87 | 88 | /reference/FirebaseSocial.html 89 | 90 | 91 | /reference/FirebaseUI.html 92 | 93 | 94 | /reference/RealtimeDatabase.html 95 | 96 | 97 | /reference/Storage.html 98 | 99 | 100 | /reference/check_installed.html 101 | 102 | 103 | /reference/check_providers.html 104 | 105 | 106 | /reference/check_urls.html 107 | 108 | 109 | /reference/config.html 110 | 111 | 112 | /reference/create_unique_id.html 113 | 114 | 115 | /reference/dependencies.html 116 | 117 | 118 | /reference/encryption.html 119 | 120 | 121 | /reference/get_config_from_env.html 122 | 123 | 124 | /reference/get_config_from_file.html 125 | 126 | 127 | /reference/index.html 128 | 129 | 130 | /reference/pkg_file.html 131 | 132 | 133 | /reference/read_config.html 134 | 135 | 136 | /reference/recaptcha.html 137 | 138 | 139 | /reference/reqSignin.html 140 | 141 | 142 | /reference/reqSignout.html 143 | 144 | 145 | -------------------------------------------------------------------------------- /inst/app/app.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | library(firebase) 3 | 4 | ui <- fluidPage( 5 | useFirebase(), 6 | firebaseUIContainer(), 7 | reqSignin(actionButton("signout", "Sign out")), 8 | uiOutput("msg"), 9 | plotOutput("plot") 10 | ) 11 | 12 | server <- function(input, output){ 13 | f <- FirebaseUI$ 14 | new("session")$ 15 | set_providers( 16 | email = TRUE, 17 | google = TRUE, 18 | github = TRUE, 19 | twitter = TRUE, 20 | facebook = TRUE, 21 | microsoft = TRUE 22 | )$ 23 | launch() 24 | 25 | output$plot <- renderPlot({ 26 | f$req_sign_in() # require sign in 27 | plot(cars) 28 | }) 29 | 30 | output$msg <- renderUI({ 31 | f$req_sign_in() # require sign in 32 | 33 | user <- f$get_signed_in() # get logged in user info 34 | print(user) 35 | 36 | h4("Welcome,", user$response$displayName) 37 | }) 38 | 39 | observeEvent(input$signout, { 40 | f$sign_out() 41 | }) 42 | 43 | } 44 | 45 | shinyApp(ui, server) 46 | -------------------------------------------------------------------------------- /inst/packer/analytics.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2019 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2020 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | -------------------------------------------------------------------------------- /inst/packer/auth.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2019 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | /** 36 | * @license 37 | * Copyright 2020 Google LLC 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the "License"); 40 | * you may not use this file except in compliance with the License. 41 | * You may obtain a copy of the License at 42 | * 43 | * http://www.apache.org/licenses/LICENSE-2.0 44 | * 45 | * Unless required by applicable law or agreed to in writing, software 46 | * distributed under the License is distributed on an "AS IS" BASIS, 47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | * See the License for the specific language governing permissions and 49 | * limitations under the License. 50 | */ 51 | 52 | /** 53 | * @license 54 | * Copyright 2020 Google LLC. 55 | * 56 | * Licensed under the Apache License, Version 2.0 (the "License"); 57 | * you may not use this file except in compliance with the License. 58 | * You may obtain a copy of the License at 59 | * 60 | * http://www.apache.org/licenses/LICENSE-2.0 61 | * 62 | * Unless required by applicable law or agreed to in writing, software 63 | * distributed under the License is distributed on an "AS IS" BASIS, 64 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | * See the License for the specific language governing permissions and 66 | * limitations under the License. 67 | */ 68 | 69 | /** 70 | * @license 71 | * Copyright 2021 Google LLC 72 | * 73 | * Licensed under the Apache License, Version 2.0 (the "License"); 74 | * you may not use this file except in compliance with the License. 75 | * You may obtain a copy of the License at 76 | * 77 | * http://www.apache.org/licenses/LICENSE-2.0 78 | * 79 | * Unless required by applicable law or agreed to in writing, software 80 | * distributed under the License is distributed on an "AS IS" BASIS, 81 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 82 | * See the License for the specific language governing permissions and 83 | * limitations under the License. 84 | */ 85 | 86 | /** 87 | * @license 88 | * Copyright 2022 Google LLC 89 | * 90 | * Licensed under the Apache License, Version 2.0 (the "License"); 91 | * you may not use this file except in compliance with the License. 92 | * You may obtain a copy of the License at 93 | * 94 | * http://www.apache.org/licenses/LICENSE-2.0 95 | * 96 | * Unless required by applicable law or agreed to in writing, software 97 | * distributed under the License is distributed on an "AS IS" BASIS, 98 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 99 | * See the License for the specific language governing permissions and 100 | * limitations under the License. 101 | */ 102 | -------------------------------------------------------------------------------- /inst/packer/core.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2019 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | /** 36 | * @license 37 | * Copyright 2020 Google LLC 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the "License"); 40 | * you may not use this file except in compliance with the License. 41 | * You may obtain a copy of the License at 42 | * 43 | * http://www.apache.org/licenses/LICENSE-2.0 44 | * 45 | * Unless required by applicable law or agreed to in writing, software 46 | * distributed under the License is distributed on an "AS IS" BASIS, 47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | * See the License for the specific language governing permissions and 49 | * limitations under the License. 50 | */ 51 | 52 | /** 53 | * @license 54 | * Copyright 2021 Google LLC 55 | * 56 | * Licensed under the Apache License, Version 2.0 (the "License"); 57 | * you may not use this file except in compliance with the License. 58 | * You may obtain a copy of the License at 59 | * 60 | * http://www.apache.org/licenses/LICENSE-2.0 61 | * 62 | * Unless required by applicable law or agreed to in writing, software 63 | * distributed under the License is distributed on an "AS IS" BASIS, 64 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | * See the License for the specific language governing permissions and 66 | * limitations under the License. 67 | */ 68 | 69 | /** 70 | * @license 71 | * Copyright 2022 Google LLC 72 | * 73 | * Licensed under the Apache License, Version 2.0 (the "License"); 74 | * you may not use this file except in compliance with the License. 75 | * You may obtain a copy of the License at 76 | * 77 | * http://www.apache.org/licenses/LICENSE-2.0 78 | * 79 | * Unless required by applicable law or agreed to in writing, software 80 | * distributed under the License is distributed on an "AS IS" BASIS, 81 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 82 | * See the License for the specific language governing permissions and 83 | * limitations under the License. 84 | */ 85 | -------------------------------------------------------------------------------- /inst/packer/email-link.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunkfirebase_r=self.webpackChunkfirebase_r||[]).push([[840],{345:(e,s,n)=>{n(235);var i=n(774),a=n(118);Shiny.addCustomMessageHandler("fireblaze-send-email-link",(e=>{const s=(0,a.v0)();window.localStorage.setItem("fireblazeEmailSignIn",e.email),e.config.url||(e.config.url=window.location.href),(0,a.oo)(s,e.email,e.config).then((()=>{(0,i.H9)("email_link_sent",{success:!0,response:e.email},e.ns)})).catch((function(s){(0,i.H9)("email_link_sent",{success:!1,response:s},e.ns)}))}))}},e=>{e.O(0,[818,647],(()=>(345,e(e.s=345)))),e.O()}]); -------------------------------------------------------------------------------- /inst/packer/email-password.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunkfirebase_r=self.webpackChunkfirebase_r||[]).push([[372],{429:(s,e,n)=>{n(235);var c=n(774),a=n(118);Shiny.addCustomMessageHandler("fireblaze-create-email-password",(function(s){const e=(0,a.v0)();(0,a.Xb)(e,s.email,s.password).then((function(e){(0,c.H9)("created_email_user",{success:!0,response:e},s.ns)})).catch((function(e){(0,c.H9)("created_email_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-signin-email-password",(function(s){const e=(0,a.v0)();(0,a.e5)(e,s.email,s.password).then((function(e){(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((function(e){(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-send-verification-email",(function(s){var e=(0,a.v0)().currentUser;(0,a.w$)(e).then((function(){(0,c.H9)("verification_email_sent",{success:!0,response:"successful"},s.ns)})).catch((function(e){(0,c.H9)("verification_email_sent",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-reset-email",(function(s){const e=(0,a.v0)();(0,a.LS)(e,s.email).then((function(){(0,c.H9)("reset_email_sent",{success:!0,response:"successful"},s.ns)})).catch((function(e){(0,c.H9)("reset_email_sent",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-re-authenticate",(function(s){var e=(0,a.v0)().currentUser,n=firebase.auth.EmailAuthProvider.credential(e.email,s.password);(0,a.aF)(e,n).then((function(){(0,c.H9)("re_authenticate",{success:!0,response:"successful"},s.ns)})).catch((function(e){(0,c.H9)("re_authenticate",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-set-password",(function(s){var e=(0,a.v0)().currentUser;(0,a.gQ)(e,s.password).then((function(){(0,c.H9)("set_password",{success:!0,response:"successful"},s.ns)})).catch((function(e){(0,c.H9)("set_password",{success:!1,response:e},s.ns)}))}))}},s=>{s.O(0,[818,647],(()=>(429,s(s.s=429)))),s.O()}]); -------------------------------------------------------------------------------- /inst/packer/firebaseui.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2015 Google Inc. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2017 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | /** 36 | * @license 37 | * Copyright 2019 Google LLC 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the "License"); 40 | * you may not use this file except in compliance with the License. 41 | * You may obtain a copy of the License at 42 | * 43 | * http://www.apache.org/licenses/LICENSE-2.0 44 | * 45 | * Unless required by applicable law or agreed to in writing, software 46 | * distributed under the License is distributed on an "AS IS" BASIS, 47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | * See the License for the specific language governing permissions and 49 | * limitations under the License. 50 | */ 51 | 52 | /** 53 | * @license 54 | * Copyright 2020 Google LLC 55 | * 56 | * Licensed under the Apache License, Version 2.0 (the "License"); 57 | * you may not use this file except in compliance with the License. 58 | * You may obtain a copy of the License at 59 | * 60 | * http://www.apache.org/licenses/LICENSE-2.0 61 | * 62 | * Unless required by applicable law or agreed to in writing, software 63 | * distributed under the License is distributed on an "AS IS" BASIS, 64 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | * See the License for the specific language governing permissions and 66 | * limitations under the License. 67 | */ 68 | 69 | /** 70 | * @license 71 | * Copyright 2020 Google LLC. 72 | * 73 | * Licensed under the Apache License, Version 2.0 (the "License"); 74 | * you may not use this file except in compliance with the License. 75 | * You may obtain a copy of the License at 76 | * 77 | * http://www.apache.org/licenses/LICENSE-2.0 78 | * 79 | * Unless required by applicable law or agreed to in writing, software 80 | * distributed under the License is distributed on an "AS IS" BASIS, 81 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 82 | * See the License for the specific language governing permissions and 83 | * limitations under the License. 84 | */ 85 | 86 | /** 87 | * @license 88 | * Copyright 2021 Google LLC 89 | * 90 | * Licensed under the Apache License, Version 2.0 (the "License"); 91 | * you may not use this file except in compliance with the License. 92 | * You may obtain a copy of the License at 93 | * 94 | * http://www.apache.org/licenses/LICENSE-2.0 95 | * 96 | * Unless required by applicable law or agreed to in writing, software 97 | * distributed under the License is distributed on an "AS IS" BASIS, 98 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 99 | * See the License for the specific language governing permissions and 100 | * limitations under the License. 101 | */ 102 | -------------------------------------------------------------------------------- /inst/packer/oauth.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunkfirebase_r=self.webpackChunkfirebase_r||[]).push([[199],{471:(e,s,n)=>{n(235);var r=n(774),i=n(118);let c=[];Shiny.addCustomMessageHandler("fireblaze-set-oauth-provider",(e=>{c[e.id]=new i.O4(e.provider),Object.entries(e.opts).length>0&&c[e.id].setCustomParameters(e.opts)})),Shiny.addCustomMessageHandler("fireblaze-oauth-sign-in-popup",(e=>{const s=(0,i.v0)();(0,i.rh)(s,c[e.id]).then((s=>{if(e.credentials){const e=i.O4.credentialFromResult(s);s.credentials={idToken:e.idToken,accessToken:e.accessToken}}(0,r.H9)("signed_up_user",{success:!0,response:s},e.ns)})).catch((s=>{(0,r.H9)("signed_up_user",{success:!1,response:s},e.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-oauth-sign-in-redirect",(e=>{const s=(0,i.v0)();(0,i.F6)(s,c[e.id]),(0,i.cx)().then((s=>{if(e.credentials){const e=i.O4.credentialFromResult(s);s.credentials={idToken:e.idToken,accessToken:e.accessToken}}(0,r.H9)("signed_up_user",{success:!0,response:s},e.ns)})).catch((s=>{(0,r.H9)("signed_up_user",{success:!1,response:s},e.ns)}))}))}},e=>{e.O(0,[818,647],(()=>(471,e(e.s=471)))),e.O()}]); -------------------------------------------------------------------------------- /inst/packer/phone.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunkfirebase_r=self.webpackChunkfirebase_r||[]).push([[214],{44:(e,s,n)=>{n(235);var c,a,r=n(774),i=n(118);Shiny.addCustomMessageHandler("fireblaze-phone-verify",(e=>{const s=(0,i.v0)();a||(a="firebase-recaptcha"==e.id?new i.lI(e.id,{callback:s=>{(0,r.H9)("phone_recaptcha",s,e.ns)}},s):new i.lI(e.id,{size:"invisible",callback:s=>{(0,r.H9)("phone_recaptcha",s,e.ns)}},s)),(0,i.$g)(s,e.number,a).then((s=>{c=s,(0,r.H9)("phone_verification",{success:!0,response:s},e.ns)})).catch((s=>{a.render().then((function(e){grecaptcha.reset(e)})),(0,r.H9)("phone_verification",{success:!1,response:s},e.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-phone-confirm",(e=>{c&&c.confirm(e.code).then((s=>{(0,r.H9)("phone_confirmation",{success:!0,response:s},e.ns)})).catch((s=>{(0,r.H9)("phone_confirmation",{success:!1,response:s},e.ns)}))}))}},e=>{e.O(0,[818,647],(()=>(44,e(e.s=44)))),e.O()}]); -------------------------------------------------------------------------------- /inst/packer/real-time.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2019 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | /** 36 | * @license 37 | * Copyright 2020 Google LLC 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the "License"); 40 | * you may not use this file except in compliance with the License. 41 | * You may obtain a copy of the License at 42 | * 43 | * http://www.apache.org/licenses/LICENSE-2.0 44 | * 45 | * Unless required by applicable law or agreed to in writing, software 46 | * distributed under the License is distributed on an "AS IS" BASIS, 47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | * See the License for the specific language governing permissions and 49 | * limitations under the License. 50 | */ 51 | 52 | /** 53 | * @license 54 | * Copyright 2021 Google LLC 55 | * 56 | * Licensed under the Apache License, Version 2.0 (the "License"); 57 | * you may not use this file except in compliance with the License. 58 | * You may obtain a copy of the License at 59 | * 60 | * http://www.apache.org/licenses/LICENSE-2.0 61 | * 62 | * Unless required by applicable law or agreed to in writing, software 63 | * distributed under the License is distributed on an "AS IS" BASIS, 64 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | * See the License for the specific language governing permissions and 66 | * limitations under the License. 67 | */ 68 | -------------------------------------------------------------------------------- /inst/packer/runtime.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var i=t[e]={id:e,exports:{}};return r[e](i,i.exports,o),i.exports}o.m=r,o.amdD=function(){throw new Error("define cannot be used indirect")},e=[],o.O=(r,t,n,i)=>{if(!t){var a=1/0;for(s=0;s=i)&&Object.keys(o.O).every((e=>o.O[e](t[l])))?t.splice(l--,1):(f=!1,i0&&e[s-1][2]>i;s--)e[s]=e[s-1];e[s]=[t,n,i]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{o.b=document.baseURI||self.location.href;var e={666:0};o.O.j=r=>0===e[r];var r=(r,t)=>{var n,i,[a,f,l]=t,u=0;if(a.some((r=>0!==e[r]))){for(n in f)o.o(f,n)&&(o.m[n]=f[n]);if(l)var s=l(o)}for(r&&r(t);u{n(235);var c=n(774),r=n(118);let u=new r.c4,i=new r._O,a=new r.GH,d=new r.hJ;Shiny.addCustomMessageHandler("fireblaze-google-scope",(s=>{d.addScope(s)})),Shiny.addCustomMessageHandler("fireblaze-google-sign-in-popup",(s=>{const e=(0,r.v0)();(0,r.rh)(e,d).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-google-sign-in-redirect",(s=>{const e=(0,r.v0)();(0,r.F6)(e,d),(0,r.cx)(e).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-facebook-scope",(s=>{i.addScope(s)})),Shiny.addCustomMessageHandler("fireblaze-facebook-sign-in-popup",(s=>{const e=(0,r.v0)();(0,r.rh)(e,i).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-facebook-sign-in-redirect",(s=>{const e=(0,r.v0)();(0,r.F6)(e,i),(0,r.cx)(e).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-github-scope",(s=>{a.addScope(s)})),Shiny.addCustomMessageHandler("fireblaze-github-sign-in-popup",(s=>{const e=(0,r.v0)();(0,r.rh)(e,a).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-github-sign-in-redirect",(s=>{const e=(0,r.v0)();(0,r.F6)(e,a),(0,r.cx)(e).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-twitter-scope",(s=>{u.addScope(s)})),Shiny.addCustomMessageHandler("fireblaze-twitter-sign-in-popup",(s=>{const e=(0,r.v0)();(0,r.rh)(e,u).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))})),Shiny.addCustomMessageHandler("fireblaze-twitter-sign-in-redirect",(s=>{const e=(0,r.v0)();(0,r.F6)(e,u),(0,r.cx)(e).then((e=>{(0,c.H9)("signed_up_user",{success:!0,response:e},s.ns)})).catch((e=>{(0,c.H9)("signed_up_user",{success:!1,response:e},s.ns)}))}))}},s=>{s.O(0,[818,647],(()=>(960,s(s.s=960)))),s.O()}]); -------------------------------------------------------------------------------- /inst/packer/storage.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2017 Google LLC 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2019 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | /** 36 | * @license 37 | * Copyright 2021 Google LLC 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the "License"); 40 | * you may not use this file except in compliance with the License. 41 | * You may obtain a copy of the License at 42 | * 43 | * http://www.apache.org/licenses/LICENSE-2.0 44 | * 45 | * Unless required by applicable law or agreed to in writing, software 46 | * distributed under the License is distributed on an "AS IS" BASIS, 47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | * See the License for the specific language governing permissions and 49 | * limitations under the License. 50 | */ 51 | -------------------------------------------------------------------------------- /inst/packer/ui.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * @license 3 | * Copyright 2015 Google Inc. All Rights Reserved. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | 18 | /** 19 | * @license 20 | * Copyright 2017 Google LLC 21 | * 22 | * Licensed under the Apache License, Version 2.0 (the "License"); 23 | * you may not use this file except in compliance with the License. 24 | * You may obtain a copy of the License at 25 | * 26 | * http://www.apache.org/licenses/LICENSE-2.0 27 | * 28 | * Unless required by applicable law or agreed to in writing, software 29 | * distributed under the License is distributed on an "AS IS" BASIS, 30 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 | * See the License for the specific language governing permissions and 32 | * limitations under the License. 33 | */ 34 | 35 | /** 36 | * @license 37 | * Copyright 2019 Google LLC 38 | * 39 | * Licensed under the Apache License, Version 2.0 (the "License"); 40 | * you may not use this file except in compliance with the License. 41 | * You may obtain a copy of the License at 42 | * 43 | * http://www.apache.org/licenses/LICENSE-2.0 44 | * 45 | * Unless required by applicable law or agreed to in writing, software 46 | * distributed under the License is distributed on an "AS IS" BASIS, 47 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 48 | * See the License for the specific language governing permissions and 49 | * limitations under the License. 50 | */ 51 | 52 | /** 53 | * @license 54 | * Copyright 2020 Google LLC 55 | * 56 | * Licensed under the Apache License, Version 2.0 (the "License"); 57 | * you may not use this file except in compliance with the License. 58 | * You may obtain a copy of the License at 59 | * 60 | * http://www.apache.org/licenses/LICENSE-2.0 61 | * 62 | * Unless required by applicable law or agreed to in writing, software 63 | * distributed under the License is distributed on an "AS IS" BASIS, 64 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 65 | * See the License for the specific language governing permissions and 66 | * limitations under the License. 67 | */ 68 | 69 | /** 70 | * @license 71 | * Copyright 2021 Google LLC 72 | * 73 | * Licensed under the Apache License, Version 2.0 (the "License"); 74 | * you may not use this file except in compliance with the License. 75 | * You may obtain a copy of the License at 76 | * 77 | * http://www.apache.org/licenses/LICENSE-2.0 78 | * 79 | * Unless required by applicable law or agreed to in writing, software 80 | * distributed under the License is distributed on an "AS IS" BASIS, 81 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 82 | * See the License for the specific language governing permissions and 83 | * limitations under the License. 84 | */ 85 | -------------------------------------------------------------------------------- /inst/packer/utilities.js: -------------------------------------------------------------------------------- 1 | "use strict";(self.webpackChunkfirebase_r=self.webpackChunkfirebase_r||[]).push([[647],{774:(e,s,i)=>{i.d(s,{H9:()=>o,T1:()=>t,eL:()=>n,fh:()=>l,k_:()=>a,qm:()=>h}),i(235);var r=i(118);const a=e=>{if("none"!=e)return"memory"==e?r.BV:"session"==e?r.aT:r.a$},n=e=>{for(var s=document.getElementsByClassName("fireblaze__requires__signin"),i=0;i{for(var s=document.getElementsByClassName("fireblaze__requires__signout"),i=0;i{i||(i=window.globalNs),Shiny.setInputValue(`${i}fireblaze_${e}`,s)},t=(e,s,i)=>{i||(i=window.globalNs),Shiny.setInputValue(`${i}${e}`,s)},h=e=>{if(!e)return;const s=(0,r.v0)();s.languageCode="browser"!=e?e:s.useDeviceLanguage()}},235:e=>{e.exports=Shiny}},e=>{e.O(0,[818],(()=>(774,e(e.s=774)))),e.O()}]); -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | check: document 2 | Rscript -e "devtools::check()" 3 | 4 | document: bundle 5 | Rscript -e "devtools::document()" 6 | 7 | bundle: 8 | Rscript -e "packer::bundle()" 9 | -------------------------------------------------------------------------------- /man/Firebase.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/class-core.R 3 | \name{Firebase} 4 | \alias{Firebase} 5 | \title{Firebase} 6 | \value{ 7 | An object of class \code{Firebase}. 8 | } 9 | \description{ 10 | Core Firebase class. 11 | } 12 | \section{Public fields}{ 13 | \if{html}{\out{
    }} 14 | \describe{ 15 | \item{\code{session}}{A valid Shiny session.} 16 | } 17 | \if{html}{\out{
    }} 18 | } 19 | \section{Methods}{ 20 | \subsection{Public methods}{ 21 | \itemize{ 22 | \item \href{#method-Firebase-new}{\code{Firebase$new()}} 23 | \item \href{#method-Firebase-expose_app}{\code{Firebase$expose_app()}} 24 | \item \href{#method-Firebase-print}{\code{Firebase$print()}} 25 | \item \href{#method-Firebase-clone}{\code{Firebase$clone()}} 26 | } 27 | } 28 | \if{html}{\out{
    }} 29 | \if{html}{\out{}} 30 | \if{latex}{\out{\hypertarget{method-Firebase-new}{}}} 31 | \subsection{Method \code{new()}}{ 32 | \subsection{Usage}{ 33 | \if{html}{\out{
    }}\preformatted{Firebase$new( 34 | config_path = "firebase.rds", 35 | session = shiny::getDefaultReactiveDomain() 36 | )}\if{html}{\out{
    }} 37 | } 38 | 39 | \subsection{Arguments}{ 40 | \if{html}{\out{
    }} 41 | \describe{ 42 | \item{\code{config_path}}{Path to the configuration file as created by \code{\link{firebase_config}}.} 43 | 44 | \item{\code{session}}{A valid shiny session.} 45 | } 46 | \if{html}{\out{
    }} 47 | } 48 | \subsection{Details}{ 49 | Initialise Firebase 50 | 51 | Initialises the Firebase application client-side. 52 | } 53 | 54 | \subsection{Returns}{ 55 | Invisibly return the class. 56 | } 57 | } 58 | \if{html}{\out{
    }} 59 | \if{html}{\out{}} 60 | \if{latex}{\out{\hypertarget{method-Firebase-expose_app}{}}} 61 | \subsection{Method \code{expose_app()}}{ 62 | \subsection{Usage}{ 63 | \if{html}{\out{
    }}\preformatted{Firebase$expose_app()}\if{html}{\out{
    }} 64 | } 65 | 66 | \subsection{Details}{ 67 | Expose App 68 | 69 | Expose the \code{firebaseApp} object product of \code{initializeApp()} by 70 | attaching it to the \code{window}: access it with \code{window.firebaseApp}. 71 | } 72 | 73 | } 74 | \if{html}{\out{
    }} 75 | \if{html}{\out{}} 76 | \if{latex}{\out{\hypertarget{method-Firebase-print}{}}} 77 | \subsection{Method \code{print()}}{ 78 | \subsection{Usage}{ 79 | \if{html}{\out{
    }}\preformatted{Firebase$print()}\if{html}{\out{
    }} 80 | } 81 | 82 | \subsection{Details}{ 83 | Print the class 84 | } 85 | 86 | } 87 | \if{html}{\out{
    }} 88 | \if{html}{\out{}} 89 | \if{latex}{\out{\hypertarget{method-Firebase-clone}{}}} 90 | \subsection{Method \code{clone()}}{ 91 | The objects of this class are cloneable with this method. 92 | \subsection{Usage}{ 93 | \if{html}{\out{
    }}\preformatted{Firebase$clone(deep = FALSE)}\if{html}{\out{
    }} 94 | } 95 | 96 | \subsection{Arguments}{ 97 | \if{html}{\out{
    }} 98 | \describe{ 99 | \item{\code{deep}}{Whether to make a deep clone.} 100 | } 101 | \if{html}{\out{
    }} 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /man/check_installed.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{check_installed} 4 | \alias{check_installed} 5 | \title{Check that a package installed} 6 | \usage{ 7 | check_installed(pkg) 8 | } 9 | \arguments{ 10 | \item{pkg}{Package name.} 11 | } 12 | \description{ 13 | Checks that a package is installed, throws 14 | an error if it is not. 15 | } 16 | \keyword{internal} 17 | -------------------------------------------------------------------------------- /man/check_providers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{check_providers} 4 | \alias{check_providers} 5 | \title{Check Providers} 6 | \usage{ 7 | check_providers(opts) 8 | } 9 | \arguments{ 10 | \item{opts}{Options to check.} 11 | } 12 | \description{ 13 | Check if providers have been set. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/check_urls.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{check_urls} 4 | \alias{check_urls} 5 | \title{Check URLs} 6 | \usage{ 7 | check_urls(fireblaze_ui) 8 | } 9 | \arguments{ 10 | \item{fireblaze_ui}{An object of class \code{\link{FirebaseUI}}.} 11 | } 12 | \description{ 13 | Check that tos and privacy policy urls are set. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/config.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/config.R 3 | \name{config} 4 | \alias{config} 5 | \alias{firebase_config} 6 | \title{Config} 7 | \usage{ 8 | firebase_config( 9 | api_key, 10 | project_id, 11 | auth_domain = NULL, 12 | storage_bucket = NULL, 13 | app_id = NULL, 14 | database_url = NULL, 15 | overwrite = FALSE 16 | ) 17 | } 18 | \arguments{ 19 | \item{api_key}{API key of your project.} 20 | 21 | \item{project_id}{Id of your web project.} 22 | 23 | \item{auth_domain}{Authentication domain, if \code{NULL} 24 | attempts to build firebase's default domain.} 25 | 26 | \item{storage_bucket}{URl to the bucket. if \code{NULL} 27 | attempts to build firebase's default storage domain.} 28 | 29 | \item{app_id}{Application ID, necessary for Analytics.} 30 | 31 | \item{database_url}{URL to the database, required to use 32 | the \code{RealtimeDatabase}.} 33 | 34 | \item{overwrite}{Whether to overwrite any existing configuration file.} 35 | } 36 | \value{ 37 | Path to file. 38 | } 39 | \description{ 40 | Configure Firebase, either using a config file or by setting 41 | environment variables (see section below). 42 | } 43 | \details{ 44 | Creates the configuration file necessary to running fireblaze. 45 | Note that if you changed the project you must use said ID 46 | here, not the one originally created by Google. 47 | 48 | Classes of the package look first for the configuration file 49 | then, if not found look for the environment variables. 50 | } 51 | \note{ 52 | Do not share this file with anyone. 53 | } 54 | \section{Environment Variables}{ 55 | 56 | \itemize{ 57 | \item \code{FIREBASE_API_KEY} 58 | \item \code{FIREBASE_PROJECT_ID} 59 | \item \code{FIREBASE_AUTH_DOMAIN} 60 | \item \code{FIREBASE_STORAGE_BUCKET} 61 | \item \code{FIREBASE_APP_ID} 62 | \item \code{FIREBASE_DATABASE_URL} 63 | } 64 | } 65 | 66 | \examples{ 67 | \dontrun{firebase_config("xXxxx", "my-project")} 68 | 69 | } 70 | -------------------------------------------------------------------------------- /man/create_unique_id.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{create_unique_id} 4 | \alias{create_unique_id} 5 | \title{ID} 6 | \usage{ 7 | create_unique_id() 8 | } 9 | \description{ 10 | Generates a unique id. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/dependencies.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dependencies.R 3 | \name{dependencies} 4 | \alias{dependencies} 5 | \alias{useFirebase} 6 | \alias{useFirebaseUI} 7 | \alias{firebaseUIContainer} 8 | \title{Dependencies} 9 | \usage{ 10 | useFirebase(analytics = FALSE, firestore = FALSE) 11 | 12 | useFirebaseUI(...) 13 | 14 | firebaseUIContainer() 15 | } 16 | \arguments{ 17 | \item{analytics}{Deprecated. Whether to include analytics.} 18 | 19 | \item{firestore}{Whether to include firestore.} 20 | 21 | \item{...}{Ignored, for backwards compatibility.} 22 | } 23 | \value{ 24 | No return value, called for side effects. 25 | } 26 | \description{ 27 | Include dependencies in your Shiny application. 28 | \code{use_firebase} \emph{must} be included in 29 | every application. 30 | } 31 | \details{ 32 | Place \code{useFirebaseUI} \emph{where} you want 33 | the pre-built UI to be placed. Otherwise one 34 | } 35 | \section{Functions}{ 36 | 37 | \itemize{ 38 | \item{\code{useFirebase} Is required for every app that uses this package} 39 | \item{\code{useFirebaseUI} Is required for applications that use \code{\link{FirebaseUI}}} 40 | \item{\code{firebaseUIContainer} To place the container of the pre-built UI where desired} 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /man/encryption.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/config.R 3 | \name{encryption} 4 | \alias{encryption} 5 | \alias{.enc} 6 | \alias{.dec} 7 | \title{Encryption} 8 | \usage{ 9 | .enc(x) 10 | 11 | .dec(x) 12 | } 13 | \arguments{ 14 | \item{x}{Value to encrypt.} 15 | } 16 | \description{ 17 | Encrypt and decrypt strings. 18 | } 19 | \keyword{internal} 20 | -------------------------------------------------------------------------------- /man/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/man/figures/logo.png -------------------------------------------------------------------------------- /man/get_config_from_env.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/config.R 3 | \name{get_config_from_env} 4 | \alias{get_config_from_env} 5 | \title{Config from Environment Variables} 6 | \usage{ 7 | get_config_from_env() 8 | } 9 | \description{ 10 | Builds the configuration object from environment variables. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/get_config_from_file.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/config.R 3 | \name{get_config_from_file} 4 | \alias{get_config_from_file} 5 | \title{Config from Environment File} 6 | \usage{ 7 | get_config_from_file(path = "firebase.rds") 8 | } 9 | \description{ 10 | Builds the configuration object from config file. 11 | } 12 | \keyword{internal} 13 | -------------------------------------------------------------------------------- /man/pkg_file.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/utils.R 3 | \name{pkg_file} 4 | \alias{pkg_file} 5 | \title{Get Path} 6 | \usage{ 7 | pkg_file(path) 8 | } 9 | \arguments{ 10 | \item{path}{Path to file in \code{inst} directory.} 11 | } 12 | \value{ 13 | Pkg path. 14 | } 15 | \description{ 16 | Get path to internal file. 17 | } 18 | \keyword{internal} 19 | -------------------------------------------------------------------------------- /man/read_config.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/config.R 3 | \name{read_config} 4 | \alias{read_config} 5 | \title{Config Internal} 6 | \usage{ 7 | read_config(path = "firebase.rds") 8 | } 9 | \arguments{ 10 | \item{path}{Path to config file} 11 | } 12 | \description{ 13 | Read and checks config. 14 | } 15 | \keyword{internal} 16 | -------------------------------------------------------------------------------- /man/recaptcha.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/class-phone.R 3 | \name{recaptcha} 4 | \alias{recaptcha} 5 | \alias{recaptchaUI} 6 | \title{Recaptcha} 7 | \usage{ 8 | recaptchaUI( 9 | ns = function(x) { 10 | x 11 | } 12 | ) 13 | } 14 | \arguments{ 15 | \item{ns}{Namespace, optional, only required if using 16 | this function in multiple places.} 17 | } 18 | \description{ 19 | Add the recaptcha, require for the \code{FirebasePhone} 20 | class. 21 | } 22 | -------------------------------------------------------------------------------- /man/reqSignin.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toggle.R 3 | \name{reqSignin} 4 | \alias{reqSignin} 5 | \title{Requires Signin} 6 | \usage{ 7 | reqSignin(...) 8 | } 9 | \arguments{ 10 | \item{...}{Any valid \link[shiny]{tags}.} 11 | } 12 | \value{ 13 | No return value, called for side effects. 14 | } 15 | \description{ 16 | Define UI element that require the user to be signed in. This 17 | will hide them \emph{viusally} until the user signs in. 18 | Note that this is not secure as someone can easily change the 19 | CSS when visiting the page to reveal those elements. 20 | } 21 | \seealso{ 22 | \code{\link{reqSignout}} 23 | } 24 | -------------------------------------------------------------------------------- /man/reqSignout.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/toggle.R 3 | \name{reqSignout} 4 | \alias{reqSignout} 5 | \title{Requires Signout} 6 | \usage{ 7 | reqSignout(...) 8 | } 9 | \arguments{ 10 | \item{...}{Any valid \link[shiny]{tags}.} 11 | } 12 | \description{ 13 | Define UI element that requires \emph{no} user to be signed in. This 14 | will hide them \emph{viusally} if no user is signed in. 15 | Note that this is not secure as someone can easily change the 16 | CSS when visiting the page to reveal those elements. 17 | } 18 | \seealso{ 19 | \code{\link{reqSignin}} 20 | } 21 | -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: firebase 2 | 3 | theme: 4 | name: material 5 | logo: logo.png 6 | favicon: logo.png 7 | palette: 8 | scheme: slate 9 | primary: blue 10 | accent: orange 11 | font: 12 | text: Raleway 13 | code: JetBrains Mono 14 | features: 15 | - navigation.sections 16 | - toc.integrate 17 | - search.suggest 18 | 19 | repo_url: https://github.com/JohnCoene/firebase 20 | repo_name: Github 21 | site_description: Google Firebase for the shiny framework. 22 | site_author: John Coene 23 | copyright: Copyright © 2023 John Coene 24 | 25 | google_analytics: 26 | - UA-74544116-1 27 | - auto 28 | 29 | markdown_extensions: 30 | - admonition 31 | - meta 32 | - smarty 33 | - pymdownx.highlight: 34 | linenums: false 35 | use_pygments: true 36 | pygments_style: native 37 | noclasses: true 38 | - pymdownx.details 39 | - pymdownx.superfences 40 | - pymdownx.tabbed 41 | - pymdownx.inlinehilite 42 | - attr_list 43 | - toc: 44 | permalink: True 45 | separator: "-" 46 | - pymdownx.emoji: 47 | emoji_index: !!python/name:materialx.emoji.twemoji 48 | emoji_generator: !!python/name:materialx.emoji.to_svg 49 | 50 | nav: 51 | - Home: index.md 52 | - Get Started: 53 | - Project Setup: guide/get-started.md 54 | - Config: guide/config.md 55 | - Storage: 56 | - Usage: storage.md 57 | - Database: 58 | - Usage: real-time.md 59 | - Analytics: 60 | - Usage: analytics.md 61 | - Authentication: 62 | - Prebuilt UI: auth/ui.md 63 | - Social Login: auth/social.md 64 | - Email & Password: auth/email-password.md 65 | - Email Link: auth/email-link.md 66 | - OAuth Providers: auth/oauth-providers.md 67 | - Phone: auth/phone.md 68 | - Manage Users: auth/manage.md 69 | - State Persistence: auth/state-persistence.md 70 | - Auth Flow: auth/flow.md 71 | - Demo Code: auth/demo.md 72 | - Misc: 73 | - Changelog: misc/changelog.md 74 | - License: misc/license.md 75 | - Code of Conduct: misc/coc.md 76 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "firebase-r", 3 | "version": "1.0.0", 4 | "description": "
    ", 5 | "main": "index.js", 6 | "directories": { 7 | "doc": "docs", 8 | "man": "man" 9 | }, 10 | "scripts": { 11 | "test": "echo \"Error: no test specified\" && exit 1", 12 | "none": "webpack --config webpack.dev.js --mode=none", 13 | "development": "webpack --config webpack.dev.js", 14 | "production": "webpack --config webpack.prod.js", 15 | "watch": "webpack --config webpack.dev.js -d --watch" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/JohnCoene/firebase.git" 20 | }, 21 | "keywords": [], 22 | "author": "", 23 | "license": "ISC", 24 | "bugs": { 25 | "url": "https://github.com/JohnCoene/firebase/issues" 26 | }, 27 | "homepage": "https://github.com/JohnCoene/firebase#readme", 28 | "devDependencies": { 29 | "@babel/core": "^7.16.0", 30 | "@babel/preset-env": "^7.16.0", 31 | "babel-loader": "^8.2.3", 32 | "css-loader": "^6.5.0", 33 | "style-loader": "^3.3.1", 34 | "webpack": "^5.61.0", 35 | "webpack-cli": "^4.9.1", 36 | "webpack-merge": "^5.8.0" 37 | }, 38 | "dependencies": { 39 | "firebase": "^9.6.7", 40 | "firebaseui": "^6.0.0" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /pkgdown/favicon/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/apple-touch-icon.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/favicon-16x16.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/favicon-32x32.png -------------------------------------------------------------------------------- /pkgdown/favicon/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/pkgdown/favicon/favicon.ico -------------------------------------------------------------------------------- /site/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /site/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /site/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /site/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /site/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /site/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/apple-touch-icon.png -------------------------------------------------------------------------------- /site/articles/firebase_email_password.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/firebase_email_password.gif -------------------------------------------------------------------------------- /site/articles/firebase_redirect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/firebase_redirect.png -------------------------------------------------------------------------------- /site/articles/firebase_yahoo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/firebase_yahoo.png -------------------------------------------------------------------------------- /site/articles/fireblaze_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_github.png -------------------------------------------------------------------------------- /site/articles/fireblaze_github_popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_github_popup.png -------------------------------------------------------------------------------- /site/articles/fireblaze_google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_google.png -------------------------------------------------------------------------------- /site/articles/fireblaze_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_home.png -------------------------------------------------------------------------------- /site/articles/fireblaze_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_project.png -------------------------------------------------------------------------------- /site/articles/fireblaze_signin_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_signin_method.png -------------------------------------------------------------------------------- /site/articles/fireblaze_social.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_social.gif -------------------------------------------------------------------------------- /site/articles/fireblaze_step_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_step_1.png -------------------------------------------------------------------------------- /site/articles/fireblaze_step_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_step_2.png -------------------------------------------------------------------------------- /site/articles/fireblaze_users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblaze_users.png -------------------------------------------------------------------------------- /site/articles/fireblazer_project_setup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/fireblazer_project_setup1.png -------------------------------------------------------------------------------- /site/articles/github_oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/github_oauth.png -------------------------------------------------------------------------------- /site/articles/ui_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/articles/ui_simple.png -------------------------------------------------------------------------------- /site/assets/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/assets/images/favicon.png -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.hi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hi=function(){this.pipeline.reset(),this.pipeline.add(e.hi.trimmer,e.hi.stopWordFilter,e.hi.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.hi.stemmer))},e.hi.wordCharacters="ऀ-ःऄ-एऐ-टठ-यर-िी-ॏॐ-य़ॠ-९॰-ॿa-zA-Za-zA-Z0-90-9",e.hi.trimmer=e.trimmerSupport.generateTrimmer(e.hi.wordCharacters),e.Pipeline.registerFunction(e.hi.trimmer,"trimmer-hi"),e.hi.stopWordFilter=e.generateStopWordFilter("अत अपना अपनी अपने अभी अंदर आदि आप इत्यादि इन इनका इन्हीं इन्हें इन्हों इस इसका इसकी इसके इसमें इसी इसे उन उनका उनकी उनके उनको उन्हीं उन्हें उन्हों उस उसके उसी उसे एक एवं एस ऐसे और कई कर करता करते करना करने करें कहते कहा का काफ़ी कि कितना किन्हें किन्हों किया किर किस किसी किसे की कुछ कुल के को कोई कौन कौनसा गया घर जब जहाँ जा जितना जिन जिन्हें जिन्हों जिस जिसे जीधर जैसा जैसे जो तक तब तरह तिन तिन्हें तिन्हों तिस तिसे तो था थी थे दबारा दिया दुसरा दूसरे दो द्वारा न नके नहीं ना निहायत नीचे ने पर पहले पूरा पे फिर बनी बही बहुत बाद बाला बिलकुल भी भीतर मगर मानो मे में यदि यह यहाँ यही या यिह ये रखें रहा रहे ऱ्वासा लिए लिये लेकिन व वग़ैरह वर्ग वह वहाँ वहीं वाले वुह वे वो सकता सकते सबसे सभी साथ साबुत साभ सारा से सो संग ही हुआ हुई हुए है हैं हो होता होती होते होना होने".split(" ")),e.hi.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var r=e.wordcut;r.init(),e.hi.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(r){return isLunr2?new e.Token(r.toLowerCase()):r.toLowerCase()});var t=i.toString().toLowerCase().replace(/^\s+/,"");return r.cut(t).split("|")},e.Pipeline.registerFunction(e.hi.stemmer,"stemmer-hi"),e.Pipeline.registerFunction(e.hi.stopWordFilter,"stopWordFilter-hi")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.hy.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.hy=function(){this.pipeline.reset(),this.pipeline.add(e.hy.trimmer,e.hy.stopWordFilter)},e.hy.wordCharacters="[A-Za-z԰-֏ff-ﭏ]",e.hy.trimmer=e.trimmerSupport.generateTrimmer(e.hy.wordCharacters),e.Pipeline.registerFunction(e.hy.trimmer,"trimmer-hy"),e.hy.stopWordFilter=e.generateStopWordFilter("դու և եք էիր էիք հետո նաև նրանք որը վրա է որ պիտի են այս մեջ ն իր ու ի այդ որոնք այն կամ էր մի ես համար այլ իսկ էին ենք հետ ին թ էինք մենք նրա նա դուք եմ էի ըստ որպես ում".split(" ")),e.Pipeline.registerFunction(e.hy.stopWordFilter,"stopWordFilter-hy"),e.hy.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}(),e.Pipeline.registerFunction(e.hy.stemmer,"stemmer-hy")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.ja.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.ja=function(){this.pipeline.reset(),this.pipeline.add(e.ja.trimmer,e.ja.stopWordFilter,e.ja.stemmer),r?this.tokenizer=e.ja.tokenizer:(e.tokenizer&&(e.tokenizer=e.ja.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.ja.tokenizer))};var t=new e.TinySegmenter;e.ja.tokenizer=function(i){var n,o,s,p,a,u,m,l,c,f;if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t.toLowerCase()):t.toLowerCase()});for(o=i.toString().toLowerCase().replace(/^\s+/,""),n=o.length-1;n>=0;n--)if(/\S/.test(o.charAt(n))){o=o.substring(0,n+1);break}for(a=[],s=o.length,c=0,l=0;c<=s;c++)if(u=o.charAt(c),m=c-l,u.match(/\s/)||c==s){if(m>0)for(p=t.segment(o.slice(l,c)).filter(function(e){return!!e}),f=l,n=0;n=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor++,!0}return!1},in_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e<=s&&e>=i&&(e-=i,t[e>>3]&1<<(7&e)))return this.cursor--,!0}return!1},out_grouping:function(t,i,s){if(this.cursors||e>3]&1<<(7&e)))return this.cursor++,!0}return!1},out_grouping_b:function(t,i,s){if(this.cursor>this.limit_backward){var e=r.charCodeAt(this.cursor-1);if(e>s||e>3]&1<<(7&e)))return this.cursor--,!0}return!1},eq_s:function(t,i){if(this.limit-this.cursor>1),f=0,l=o0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n+_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n+_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},find_among_b:function(t,i){for(var s=0,e=i,n=this.cursor,u=this.limit_backward,o=0,h=0,c=!1;;){for(var a=s+(e-s>>1),f=0,l=o=0;m--){if(n-l==u){f=-1;break}if(f=r.charCodeAt(n-1-l)-_.s[m])break;l++}if(f<0?(e=a,h=l):(s=a,o=l),e-s<=1){if(s>0||e==s||c)break;c=!0}}for(;;){var _=t[s];if(o>=_.s_size){if(this.cursor=n-_.s_size,!_.method)return _.result;var b=_.method();if(this.cursor=n-_.s_size,b)return _.result}if((s=_.substring_i)<0)return 0}},replace_s:function(t,i,s){var e=s.length-(i-t),n=r.substring(0,t),u=r.substring(i);return r=n+s+u,this.limit+=e,this.cursor>=i?this.cursor+=e:this.cursor>t&&(this.cursor=t),e},slice_check:function(){if(this.bra<0||this.bra>this.ket||this.ket>this.limit||this.limit>r.length)throw"faulty slice operation"},slice_from:function(r){this.slice_check(),this.replace_s(this.bra,this.ket,r)},slice_del:function(){this.slice_from("")},insert:function(r,t,i){var s=this.replace_s(r,t,i);r<=this.bra&&(this.bra+=s),r<=this.ket&&(this.ket+=s)},slice_to:function(){return this.slice_check(),r.substring(this.bra,this.ket)},eq_v_b:function(r){return this.eq_s_b(r.length,r)}}}},r.trimmerSupport={generateTrimmer:function(r){var t=new RegExp("^[^"+r+"]+"),i=new RegExp("[^"+r+"]+$");return function(r){return"function"==typeof r.update?r.update(function(r){return r.replace(t,"").replace(i,"")}):r.replace(t,"").replace(i,"")}}}}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.sv.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Lunr languages, `Swedish` language 3 | * https://github.com/MihaiValentin/lunr-languages 4 | * 5 | * Copyright 2014, Mihai Valentin 6 | * http://www.mozilla.org/MPL/ 7 | */ 8 | /*! 9 | * based on 10 | * Snowball JavaScript Library v0.3 11 | * http://code.google.com/p/urim/ 12 | * http://snowball.tartarus.org/ 13 | * 14 | * Copyright 2010, Oleg Mazko 15 | * http://www.mozilla.org/MPL/ 16 | */ 17 | 18 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.sv=function(){this.pipeline.reset(),this.pipeline.add(e.sv.trimmer,e.sv.stopWordFilter,e.sv.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.sv.stemmer))},e.sv.wordCharacters="A-Za-zªºÀ-ÖØ-öø-ʸˠ-ˤᴀ-ᴥᴬ-ᵜᵢ-ᵥᵫ-ᵷᵹ-ᶾḀ-ỿⁱⁿₐ-ₜKÅℲⅎⅠ-ↈⱠ-ⱿꜢ-ꞇꞋ-ꞭꞰ-ꞷꟷ-ꟿꬰ-ꭚꭜ-ꭤff-stA-Za-z",e.sv.trimmer=e.trimmerSupport.generateTrimmer(e.sv.wordCharacters),e.Pipeline.registerFunction(e.sv.trimmer,"trimmer-sv"),e.sv.stemmer=function(){var r=e.stemmerSupport.Among,n=e.stemmerSupport.SnowballProgram,t=new function(){function e(){var e,r=w.cursor+3;if(o=w.limit,0<=r||r<=w.limit){for(a=r;;){if(e=w.cursor,w.in_grouping(l,97,246)){w.cursor=e;break}if(w.cursor=e,w.cursor>=w.limit)return;w.cursor++}for(;!w.out_grouping(l,97,246);){if(w.cursor>=w.limit)return;w.cursor++}o=w.cursor,o=o&&(w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(u,37),w.limit_backward=r,e))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.in_grouping_b(d,98,121)&&w.slice_del()}}function i(){var e=w.limit_backward;w.cursor>=o&&(w.limit_backward=o,w.cursor=w.limit,w.find_among_b(c,7)&&(w.cursor=w.limit,w.ket=w.cursor,w.cursor>w.limit_backward&&(w.bra=--w.cursor,w.slice_del())),w.limit_backward=e)}function s(){var e,r;if(w.cursor>=o){if(r=w.limit_backward,w.limit_backward=o,w.cursor=w.limit,w.ket=w.cursor,e=w.find_among_b(m,5))switch(w.bra=w.cursor,e){case 1:w.slice_del();break;case 2:w.slice_from("lös");break;case 3:w.slice_from("full")}w.limit_backward=r}}var a,o,u=[new r("a",-1,1),new r("arna",0,1),new r("erna",0,1),new r("heterna",2,1),new r("orna",0,1),new r("ad",-1,1),new r("e",-1,1),new r("ade",6,1),new r("ande",6,1),new r("arne",6,1),new r("are",6,1),new r("aste",6,1),new r("en",-1,1),new r("anden",12,1),new r("aren",12,1),new r("heten",12,1),new r("ern",-1,1),new r("ar",-1,1),new r("er",-1,1),new r("heter",18,1),new r("or",-1,1),new r("s",-1,2),new r("as",21,1),new r("arnas",22,1),new r("ernas",22,1),new r("ornas",22,1),new r("es",21,1),new r("ades",26,1),new r("andes",26,1),new r("ens",21,1),new r("arens",29,1),new r("hetens",29,1),new r("erns",21,1),new r("at",-1,1),new r("andet",-1,1),new r("het",-1,1),new r("ast",-1,1)],c=[new r("dd",-1,-1),new r("gd",-1,-1),new r("nn",-1,-1),new r("dt",-1,-1),new r("gt",-1,-1),new r("kt",-1,-1),new r("tt",-1,-1)],m=[new r("ig",-1,1),new r("lig",0,1),new r("els",-1,1),new r("fullt",-1,3),new r("löst",-1,2)],l=[17,65,16,1,0,0,0,0,0,0,0,0,0,0,0,0,24,0,32],d=[119,127,149],w=new n;this.setCurrent=function(e){w.setCurrent(e)},this.getCurrent=function(){return w.getCurrent()},this.stem=function(){var r=w.cursor;return e(),w.limit_backward=r,w.cursor=w.limit,t(),w.cursor=w.limit,i(),w.cursor=w.limit,s(),!0}};return function(e){return"function"==typeof e.update?e.update(function(e){return t.setCurrent(e),t.stem(),t.getCurrent()}):(t.setCurrent(e),t.stem(),t.getCurrent())}}(),e.Pipeline.registerFunction(e.sv.stemmer,"stemmer-sv"),e.sv.stopWordFilter=e.generateStopWordFilter("alla allt att av blev bli blir blivit de dem den denna deras dess dessa det detta dig din dina ditt du där då efter ej eller en er era ert ett från för ha hade han hans har henne hennes hon honom hur här i icke ingen inom inte jag ju kan kunde man med mellan men mig min mina mitt mot mycket ni nu när någon något några och om oss på samma sedan sig sin sina sitta själv skulle som så sådan sådana sådant till under upp ut utan vad var vara varför varit varje vars vart vem vi vid vilka vilkas vilken vilket vår våra vårt än är åt över".split(" ")),e.Pipeline.registerFunction(e.sv.stopWordFilter,"stopWordFilter-sv")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.ta.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.ta=function(){this.pipeline.reset(),this.pipeline.add(e.ta.trimmer,e.ta.stopWordFilter,e.ta.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.ta.stemmer))},e.ta.wordCharacters="஀-உஊ-ஏஐ-ஙச-ட஠-னப-யர-ஹ஺-ிீ-௉ொ-௏ௐ-௙௚-௟௠-௩௪-௯௰-௹௺-௿a-zA-Za-zA-Z0-90-9",e.ta.trimmer=e.trimmerSupport.generateTrimmer(e.ta.wordCharacters),e.Pipeline.registerFunction(e.ta.trimmer,"trimmer-ta"),e.ta.stopWordFilter=e.generateStopWordFilter("அங்கு அங்கே அது அதை அந்த அவர் அவர்கள் அவள் அவன் அவை ஆக ஆகவே ஆகையால் ஆதலால் ஆதலினால் ஆனாலும் ஆனால் இங்கு இங்கே இது இதை இந்த இப்படி இவர் இவர்கள் இவள் இவன் இவை இவ்வளவு உனக்கு உனது உன் உன்னால் எங்கு எங்கே எது எதை எந்த எப்படி எவர் எவர்கள் எவள் எவன் எவை எவ்வளவு எனக்கு எனது எனவே என் என்ன என்னால் ஏது ஏன் தனது தன்னால் தானே தான் நாங்கள் நாம் நான் நீ நீங்கள்".split(" ")),e.ta.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.ta.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.ta.stemmer,"stemmer-ta"),e.Pipeline.registerFunction(e.ta.stopWordFilter,"stopWordFilter-ta")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.te.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports?module.exports=t():t()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.te=function(){this.pipeline.reset(),this.pipeline.add(e.te.trimmer,e.te.stopWordFilter,e.te.stemmer),this.searchPipeline&&(this.searchPipeline.reset(),this.searchPipeline.add(e.te.stemmer))},e.te.wordCharacters="ఀ-ఄఅ-ఔక-హా-ౌౕ-ౖౘ-ౚౠ-ౡౢ-ౣ౦-౯౸-౿఼ఽ్ౝ౷౤౥",e.te.trimmer=e.trimmerSupport.generateTrimmer(e.te.wordCharacters),e.Pipeline.registerFunction(e.te.trimmer,"trimmer-te"),e.te.stopWordFilter=e.generateStopWordFilter("అందరూ అందుబాటులో అడగండి అడగడం అడ్డంగా అనుగుణంగా అనుమతించు అనుమతిస్తుంది అయితే ఇప్పటికే ఉన్నారు ఎక్కడైనా ఎప్పుడు ఎవరైనా ఎవరో ఏ ఏదైనా ఏమైనప్పటికి ఒక ఒకరు కనిపిస్తాయి కాదు కూడా గా గురించి చుట్టూ చేయగలిగింది తగిన తర్వాత దాదాపు దూరంగా నిజంగా పై ప్రకారం ప్రక్కన మధ్య మరియు మరొక మళ్ళీ మాత్రమే మెచ్చుకో వద్ద వెంట వేరుగా వ్యతిరేకంగా సంబంధం".split(" ")),e.te.stemmer=function(){return function(e){return"function"==typeof e.update?e.update(function(e){return e}):e}}();var t=e.wordcut;t.init(),e.te.tokenizer=function(r){if(!arguments.length||null==r||void 0==r)return[];if(Array.isArray(r))return r.map(function(t){return isLunr2?new e.Token(t.toLowerCase()):t.toLowerCase()});var i=r.toString().toLowerCase().replace(/^\s+/,"");return t.cut(i).split("|")},e.Pipeline.registerFunction(e.te.stemmer,"stemmer-te"),e.Pipeline.registerFunction(e.te.stopWordFilter,"stopWordFilter-te")}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.th.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var r="2"==e.version[0];e.th=function(){this.pipeline.reset(),this.pipeline.add(e.th.trimmer),r?this.tokenizer=e.th.tokenizer:(e.tokenizer&&(e.tokenizer=e.th.tokenizer),this.tokenizerFn&&(this.tokenizerFn=e.th.tokenizer))},e.th.wordCharacters="[฀-๿]",e.th.trimmer=e.trimmerSupport.generateTrimmer(e.th.wordCharacters),e.Pipeline.registerFunction(e.th.trimmer,"trimmer-th");var t=e.wordcut;t.init(),e.th.tokenizer=function(i){if(!arguments.length||null==i||void 0==i)return[];if(Array.isArray(i))return i.map(function(t){return r?new e.Token(t):t});var n=i.toString().replace(/^\s+/,"");return t.cut(n).split("|")}}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.vi.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r():r()(e.lunr)}(this,function(){return function(e){if(void 0===e)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===e.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");e.vi=function(){this.pipeline.reset(),this.pipeline.add(e.vi.stopWordFilter,e.vi.trimmer)},e.vi.wordCharacters="[A-Za-ẓ̀͐́͑̉̃̓ÂâÊêÔôĂ-ăĐ-đƠ-ơƯ-ư]",e.vi.trimmer=e.trimmerSupport.generateTrimmer(e.vi.wordCharacters),e.Pipeline.registerFunction(e.vi.trimmer,"trimmer-vi"),e.vi.stopWordFilter=e.generateStopWordFilter("là cái nhưng mà".split(" "))}}); -------------------------------------------------------------------------------- /site/assets/javascripts/lunr/min/lunr.zh.min.js: -------------------------------------------------------------------------------- 1 | !function(e,r){"function"==typeof define&&define.amd?define(r):"object"==typeof exports?module.exports=r(require("@node-rs/jieba")):r()(e.lunr)}(this,function(e){return function(r,t){if(void 0===r)throw new Error("Lunr is not present. Please include / require Lunr before this script.");if(void 0===r.stemmerSupport)throw new Error("Lunr stemmer support is not present. Please include / require Lunr stemmer support before this script.");var i="2"==r.version[0];r.zh=function(){this.pipeline.reset(),this.pipeline.add(r.zh.trimmer,r.zh.stopWordFilter,r.zh.stemmer),i?this.tokenizer=r.zh.tokenizer:(r.tokenizer&&(r.tokenizer=r.zh.tokenizer),this.tokenizerFn&&(this.tokenizerFn=r.zh.tokenizer))},r.zh.tokenizer=function(n){if(!arguments.length||null==n||void 0==n)return[];if(Array.isArray(n))return n.map(function(e){return i?new r.Token(e.toLowerCase()):e.toLowerCase()});t&&e.load(t);var o=n.toString().trim().toLowerCase(),s=[];e.cut(o,!0).forEach(function(e){s=s.concat(e.split(" "))}),s=s.filter(function(e){return!!e});var u=0;return s.map(function(e,t){if(i){var n=o.indexOf(e,u),s={};return s.position=[n,e.length],s.index=t,u=n,new r.Token(e,s)}return e})},r.zh.wordCharacters="\\w一-龥",r.zh.trimmer=r.trimmerSupport.generateTrimmer(r.zh.wordCharacters),r.Pipeline.registerFunction(r.zh.trimmer,"trimmer-zh"),r.zh.stemmer=function(){return function(e){return e}}(),r.Pipeline.registerFunction(r.zh.stemmer,"stemmer-zh"),r.zh.stopWordFilter=r.generateStopWordFilter("的 一 不 在 人 有 是 为 為 以 于 於 上 他 而 后 後 之 来 來 及 了 因 下 可 到 由 这 這 与 與 也 此 但 并 並 个 個 其 已 无 無 小 我 们 們 起 最 再 今 去 好 只 又 或 很 亦 某 把 那 你 乃 它 吧 被 比 别 趁 当 當 从 從 得 打 凡 儿 兒 尔 爾 该 該 各 给 給 跟 和 何 还 還 即 几 幾 既 看 据 據 距 靠 啦 另 么 麽 每 嘛 拿 哪 您 凭 憑 且 却 卻 让 讓 仍 啥 如 若 使 谁 誰 虽 雖 随 隨 同 所 她 哇 嗡 往 些 向 沿 哟 喲 用 咱 则 則 怎 曾 至 致 着 著 诸 諸 自".split(" ")),r.Pipeline.registerFunction(r.zh.stopWordFilter,"stopWordFilter-zh")}}); -------------------------------------------------------------------------------- /site/assets/stylesheets/palette.ecc896b0.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["src/assets/stylesheets/palette/_scheme.scss","../../../src/assets/stylesheets/palette.scss","src/assets/stylesheets/palette/_accent.scss","src/assets/stylesheets/palette/_primary.scss","src/assets/stylesheets/utilities/_break.scss"],"names":[],"mappings":"AA2BA,cAGE,6BAQE,YAAA,CAGA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CACA,mDAAA,CACA,6DAAA,CACA,+DAAA,CACA,gEAAA,CAGA,gDAAA,CACA,gDAAA,CAGA,4BAAA,CACA,iCAAA,CACA,kCAAA,CACA,mCAAA,CACA,mCAAA,CACA,kCAAA,CACA,iCAAA,CACA,+CAAA,CACA,6DAAA,CACA,gEAAA,CACA,4DAAA,CACA,4DAAA,CACA,6DAAA,CAGA,6CAAA,CAGA,+CAAA,CAGA,iCAAA,CAGA,uDAAA,CACA,6DAAA,CACA,2DAAA,CAGA,yDAAA,CACA,iEAAA,CAGA,mDAAA,CACA,mDAAA,CAGA,qDAAA,CACA,wDAAA,CAGA,0DAAA,CAKA,8DAAA,CAKA,0DAAA,CAzEA,iBCeF,CD+DE,kHAEE,YC7DJ,CDoFE,yDACE,4BClFJ,CDiFE,2DACE,4BC/EJ,CD8EE,gEACE,4BC5EJ,CD2EE,2DACE,4BCzEJ,CDwEE,yDACE,4BCtEJ,CDqEE,0DACE,4BCnEJ,CDkEE,gEACE,4BChEJ,CD+DE,0DACE,4BC7DJ,CD4DE,2OACE,4BCjDJ,CDwDA,+FAGE,iCCtDF,CACF,CC/CE,2BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD2CN,CCrDE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDkDN,CC5DE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDyDN,CCnEE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDgEN,CC1EE,8BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDuEN,CCjFE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD8EN,CCxFE,kCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDqFN,CC/FE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD4FN,CCtGE,4BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDmGN,CC7GE,6BACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCD0GN,CCpHE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDiHN,CC3HE,4BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCD2HN,CClIE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDkIN,CCzIE,6BACE,yBAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDyIN,CChJE,8BACE,4BAAA,CACA,2CAAA,CAIE,8BAAA,CACA,qCDgJN,CCvJE,mCACE,4BAAA,CACA,2CAAA,CAOE,yBAAA,CACA,qCDoJN,CEzJE,4BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsJN,CEjKE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8JN,CEzKE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsKN,CEjLE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8KN,CEzLE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsLN,CEjME,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8LN,CEzME,mCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsMN,CEjNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8MN,CEzNE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsNN,CEjOE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8NN,CEzOE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsON,CEjPE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFiPN,CEzPE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFyPN,CEjQE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFiQN,CEzQE,+BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAIE,+BAAA,CACA,sCFyQN,CEjRE,oCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCF8QN,CEzRE,8BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCFsRN,CEjSE,6BACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BF0RN,CE1SE,kCACE,6BAAA,CACA,oCAAA,CACA,mCAAA,CAOE,0BAAA,CACA,sCAAA,CAKA,4BFmSN,CEpRE,sEACE,4BFuRJ,CExRE,+DACE,4BF2RJ,CE5RE,iEACE,4BF+RJ,CEhSE,gEACE,4BFmSJ,CEpSE,iEACE,4BFuSJ,CE9RA,8BACE,0BAAA,CACA,sCAAA,CACA,qCAAA,CACA,+BAAA,CACA,sCAAA,CAGA,4BF+RF,CE5RE,yCACE,+BF8RJ,CE3RI,kDAEE,0CAAA,CACA,sCAAA,CAFA,UF+RN,CG3MI,mCD1EA,+CACE,0BFwRJ,CErRI,qDACE,0BFuRN,CElRE,iEACE,eFoRJ,CACF,CGtNI,sCDvDA,uCACE,oCFgRJ,CACF,CEvQA,8BACE,0BAAA,CACA,sCAAA,CACA,gCAAA,CACA,0BAAA,CACA,sCAAA,CAGA,4BFwQF,CErQE,yCACE,+BFuQJ,CEpQI,kDAEE,0CAAA,CACA,sCAAA,CAFA,UFwQN,CEjQE,yCACE,qBFmQJ,CG5NI,wCDhCA,8CACE,0BF+PJ,CACF,CGpPI,mCDJA,+CACE,0BF2PJ,CExPI,qDACE,0BF0PN,CACF,CGzOI,wCDTA,iFACE,qBFqPJ,CACF,CGjQI,sCDmBA,uCACE,qBFiPJ,CACF","file":"palette.css"} -------------------------------------------------------------------------------- /site/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /site/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /site/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/favicon-16x16.png -------------------------------------------------------------------------------- /site/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/favicon-32x32.png -------------------------------------------------------------------------------- /site/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/favicon.ico -------------------------------------------------------------------------------- /site/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /site/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/logo.png -------------------------------------------------------------------------------- /site/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $("div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /site/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.1 2 | pkgdown: 2.0.7 3 | pkgdown_sha: ~ 4 | articles: 5 | analytics: analytics.html 6 | demo: demo.html 7 | email-link: email-link.html 8 | email-password: email-password.html 9 | flow: flow.html 10 | get-started: get-started.html 11 | manage: manage.html 12 | oauth-providers: oauth-providers.html 13 | phone: phone.html 14 | social: social.html 15 | state-persistence: state-persistence.html 16 | storage: storage.html 17 | ui: ui.html 18 | last_built: 2023-07-04T12:12Z 19 | 20 | -------------------------------------------------------------------------------- /site/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/reference/Rplot001.png -------------------------------------------------------------------------------- /site/reference/figures/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/reference/figures/logo.png -------------------------------------------------------------------------------- /site/search/search_index.json: -------------------------------------------------------------------------------- 1 | {"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[]} -------------------------------------------------------------------------------- /site/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /site/sitemap.xml.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/site/sitemap.xml.gz -------------------------------------------------------------------------------- /srcjs/components/analytics.js: -------------------------------------------------------------------------------- 1 | import 'shiny' 2 | import { getAnalytics, logEvent, setUserProperties} from 'firebase/analytics'; 3 | 4 | let analytics; 5 | 6 | Shiny.addCustomMessageHandler('fireblaze-initialize-analytics', (msg) => { 7 | if(!analytics) 8 | analytics = getAnalytics(); 9 | }); 10 | 11 | Shiny.addCustomMessageHandler('fireblaze-log-event', (msg) => { 12 | if(!msg.params){ 13 | logEvent(analytics, msg.event); 14 | return; 15 | } 16 | 17 | logEvent(analytics, msg.event, msg.params); 18 | }); 19 | 20 | Shiny.addCustomMessageHandler('fireblaze-set-user-properties', (msg) => { 21 | setUserProperties(analytics, msg.props); 22 | }); 23 | -------------------------------------------------------------------------------- /srcjs/components/email-link.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { setInputValue } from '../utils'; 3 | import { sendSignInLinkToEmail, getAuth } from 'firebase/auth'; 4 | 5 | Shiny.addCustomMessageHandler('fireblaze-send-email-link', (msg) => { 6 | const auth = getAuth(); 7 | window.localStorage.setItem('fireblazeEmailSignIn', msg.email); 8 | if(!msg.config.url) 9 | msg.config.url = window.location.href; 10 | sendSignInLinkToEmail(auth, msg.email, msg.config) 11 | .then(() => { 12 | setInputValue('email_link_sent', {success: true, response: msg.email}, msg.ns); 13 | }) 14 | .catch(function(error) { 15 | setInputValue('email_link_sent', {success: false, response: error}, msg.ns); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /srcjs/components/email-password.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { setInputValue } from '../utils'; 3 | import { 4 | createUserWithEmailAndPassword, 5 | signInWithEmailAndPassword, 6 | sendPasswordResetEmail, 7 | sendEmailVerification, 8 | reauthenticateWithCredential, 9 | updatePassword, 10 | getAuth 11 | } from "firebase/auth"; 12 | 13 | // create 14 | Shiny.addCustomMessageHandler('fireblaze-create-email-password', function(msg) { 15 | const auth = getAuth(); 16 | createUserWithEmailAndPassword(auth, msg.email, msg.password) 17 | .then(function(result) { 18 | setInputValue('created_email_user', {success: true, response: result}, msg.ns); 19 | }).catch(function(error) { 20 | setInputValue('created_email_user', {success: false, response: error}, msg.ns); 21 | }); 22 | }); 23 | 24 | // sign in 25 | Shiny.addCustomMessageHandler('fireblaze-signin-email-password', function(msg) { 26 | const auth = getAuth(); 27 | signInWithEmailAndPassword(auth, msg.email, msg.password) 28 | .then(function(result) { 29 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 30 | }).catch(function(error) { 31 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 32 | }); 33 | }); 34 | 35 | // Send email verification 36 | Shiny.addCustomMessageHandler('fireblaze-send-verification-email', function(msg) { 37 | const auth = getAuth(); 38 | var user = auth.currentUser; 39 | 40 | sendEmailVerification(user) 41 | .then(function() { 42 | setInputValue('verification_email_sent', {success: true, response: 'successful'}, msg.ns) 43 | }).catch(function(error) { 44 | setInputValue('verification_email_sent', {success: false, response: error}, msg.ns) 45 | }); 46 | }); 47 | 48 | // reset email 49 | Shiny.addCustomMessageHandler('fireblaze-reset-email', function(msg) { 50 | const auth = getAuth(); 51 | 52 | sendPasswordResetEmail(auth, msg.email) 53 | .then(function() { 54 | setInputValue('reset_email_sent', {success: true, response: 'successful'}, msg.ns); 55 | }).catch(function(error) { 56 | setInputValue('reset_email_sent', {success: false, response: error}, msg.ns); 57 | }); 58 | }); 59 | 60 | // Reauthenticate 61 | Shiny.addCustomMessageHandler('fireblaze-re-authenticate', function(msg) { 62 | const auth = getAuth(); 63 | var user = auth.currentUser; 64 | var credential = firebase.auth.EmailAuthProvider.credential(user.email, msg.password); 65 | 66 | reauthenticateWithCredential(user, credential) 67 | .then(function() { 68 | setInputValue('re_authenticate', {success: true, response: 'successful'}, msg.ns); 69 | }).catch(function(error) { 70 | setInputValue('re_authenticate', {success: false, response: error}, msg.ns); 71 | }); 72 | }); 73 | 74 | // set password 75 | Shiny.addCustomMessageHandler('fireblaze-set-password', function(msg) { 76 | const auth = getAuth(); 77 | var user = auth.currentUser; 78 | 79 | updatePassword(user, msg.password) 80 | .then(function() { 81 | setInputValue('set_password', {success: true, response: 'successful'}, msg.ns); 82 | }).catch(function(error) { 83 | setInputValue('set_password', {success: false, response: error}, msg.ns); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /srcjs/components/oauth.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { setInputValue } from '../utils'; 3 | import { 4 | signInWithPopup, 5 | signInWithRedirect, 6 | getRedirectResult, 7 | getAuth, 8 | OAuthProvider 9 | } from 'firebase/auth'; 10 | 11 | let oauthProviders = []; 12 | 13 | Shiny.addCustomMessageHandler('fireblaze-set-oauth-provider', (msg) => { 14 | oauthProviders[msg.id] = new OAuthProvider(msg.provider); 15 | 16 | if(Object.entries(msg.opts).length > 0) 17 | oauthProviders[msg.id].setCustomParameters(msg.opts) 18 | }); 19 | 20 | Shiny.addCustomMessageHandler('fireblaze-oauth-sign-in-popup', (msg) => { 21 | const auth = getAuth(); 22 | signInWithPopup(auth, oauthProviders[msg.id]) 23 | .then((result) => { 24 | if(msg.credentials) { 25 | const credential = OAuthProvider.credentialFromResult(result); 26 | result.credentials = { 27 | idToken: credential.idToken, 28 | accessToken: credential.accessToken, 29 | }; 30 | } 31 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 32 | }).catch((error) => { 33 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 34 | }); 35 | }); 36 | 37 | Shiny.addCustomMessageHandler('fireblaze-oauth-sign-in-redirect', (msg) => { 38 | const auth = getAuth(); 39 | signInWithRedirect(auth, oauthProviders[msg.id]); 40 | 41 | getRedirectResult() 42 | .then((result) => { 43 | if(msg.credentials) { 44 | const credential = OAuthProvider.credentialFromResult(result); 45 | result.credentials = { 46 | idToken: credential.idToken, 47 | accessToken: credential.accessToken, 48 | }; 49 | } 50 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 51 | }).catch((error) => { 52 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 53 | }); 54 | }); 55 | -------------------------------------------------------------------------------- /srcjs/components/phone.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { setInputValue } from '../utils.js'; 3 | import { 4 | signInWithPhoneNumber, 5 | RecaptchaVerifier, 6 | getAuth, 7 | } from 'firebase/auth'; 8 | 9 | var confirmationResult; 10 | var recaptchaVerifier; 11 | 12 | Shiny.addCustomMessageHandler('fireblaze-phone-verify', msg => { 13 | const auth = getAuth(); 14 | if(!recaptchaVerifier){ 15 | 16 | if(msg.id == 'firebase-recaptcha') 17 | recaptchaVerifier = new RecaptchaVerifier(msg.id, { 18 | callback: (response) => { 19 | setInputValue( 20 | 'phone_recaptcha', 21 | response, 22 | msg.ns 23 | ); 24 | } 25 | }, auth); 26 | else 27 | recaptchaVerifier = new RecaptchaVerifier(msg.id, { 28 | size: 'invisible', 29 | callback: (response) => { 30 | setInputValue( 31 | 'phone_recaptcha', 32 | response, 33 | msg.ns 34 | ); 35 | } 36 | }, auth); 37 | } 38 | 39 | signInWithPhoneNumber(auth, msg.number, recaptchaVerifier) 40 | .then(result => { 41 | confirmationResult = result; 42 | setInputValue( 43 | 'phone_verification', 44 | {success: true, response: result}, 45 | msg.ns 46 | ); 47 | }).catch(error => { 48 | recaptchaVerifier.render().then(function(widgetId) { 49 | grecaptcha.reset(widgetId); 50 | }); 51 | setInputValue( 52 | 'phone_verification', 53 | {success: false, response: error}, 54 | msg.ns 55 | ); 56 | }); 57 | }); 58 | 59 | Shiny.addCustomMessageHandler('fireblaze-phone-confirm', msg => { 60 | if(!confirmationResult) 61 | return; 62 | 63 | confirmationResult.confirm(msg.code) 64 | .then(result => { 65 | setInputValue( 66 | 'phone_confirmation', 67 | {success: true, response: result}, 68 | msg.ns 69 | ); 70 | }).catch(error => { 71 | setInputValue( 72 | 'phone_confirmation', 73 | {success: false, response: error}, 74 | msg.ns 75 | ); 76 | }); 77 | }); 78 | -------------------------------------------------------------------------------- /srcjs/components/real-time.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { getDatabase, ref, set, update, remove, onValue } from 'firebase/database'; 3 | import { setInputValue2 } from '../utils.js'; 4 | 5 | var db; 6 | var storeRef; 7 | 8 | Shiny.addCustomMessageHandler('fireblaze-real-time-init', (msg) => { 9 | db = getDatabase(); 10 | }); 11 | 12 | Shiny.addCustomMessageHandler('fireblaze-real-time-ref', (msg) => { 13 | if(!msg.path){ 14 | storeRef = ref(db); 15 | return; 16 | } 17 | 18 | storeRef = ref(db, msg.path); 19 | }); 20 | 21 | Shiny.addCustomMessageHandler('fireblaze-real-time-on-value', (msg) => { 22 | if(msg.path) 23 | storeRef = ref(db, msg.path); 24 | 25 | onValue(storeRef, (snapshot) => { 26 | if(!msg.response) 27 | return; 28 | 29 | const data = snapshot.val(); 30 | 31 | setInputValue2( 32 | msg.response, 33 | { 34 | success: false, 35 | response: data 36 | }, 37 | msg.ns 38 | ); 39 | }); 40 | }); 41 | 42 | Shiny.addCustomMessageHandler('fireblaze-real-time-set', (msg) => { 43 | if(msg.path) 44 | storeRef = ref(db, msg.path); 45 | 46 | set(storeRef, msg.data) 47 | .then(() => { 48 | if(!msg.response) 49 | return; 50 | 51 | setInputValue2( 52 | msg.response, 53 | { 54 | success: true, 55 | response: [] 56 | }, 57 | msg.ns 58 | ); 59 | }) 60 | .catch(error => { 61 | if(!msg.response) 62 | return; 63 | 64 | setInputValue2( 65 | msg.response, 66 | { 67 | success: false, 68 | response: error, 69 | }, 70 | msg.ns 71 | ); 72 | }) 73 | }); 74 | 75 | Shiny.addCustomMessageHandler('fireblaze-real-time-update', (msg) => { 76 | if(msg.path) 77 | storeRef = ref(db, msg.path); 78 | 79 | update(storeRef, msg.data) 80 | .then(() => { 81 | if(!msg.response) 82 | return; 83 | 84 | setInputValue2( 85 | msg.response, 86 | { 87 | success: true, 88 | response: [] 89 | }, 90 | msg.ns 91 | ); 92 | }) 93 | .catch(error => { 94 | if(!msg.response) 95 | return; 96 | 97 | setInputValue2( 98 | msg.response, 99 | { 100 | success: false, 101 | response: error, 102 | }, 103 | msg.ns 104 | ); 105 | }) 106 | }); 107 | 108 | Shiny.addCustomMessageHandler('fireblaze-real-time-delete', (msg) => { 109 | if(msg.path) 110 | storeRef = ref(db, msg.path); 111 | 112 | remove(storeRef, msg.data) 113 | .then(() => { 114 | if(!msg.response) 115 | return; 116 | 117 | setInputValue2( 118 | msg.response, 119 | { 120 | success: true, 121 | response: [] 122 | }, 123 | msg.ns 124 | ); 125 | }) 126 | .catch(error => { 127 | if(!msg.response) 128 | return; 129 | 130 | setInputValue2( 131 | msg.response, 132 | { 133 | success: false, 134 | response: error, 135 | }, 136 | msg.ns 137 | ); 138 | }) 139 | }); 140 | -------------------------------------------------------------------------------- /srcjs/components/social.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { setInputValue } from '../utils'; 3 | import { 4 | TwitterAuthProvider, 5 | FacebookAuthProvider, 6 | GithubAuthProvider, 7 | GoogleAuthProvider, 8 | getAuth, 9 | signInWithPopup, 10 | signInWithRedirect, 11 | getRedirectResult 12 | } from 'firebase/auth' 13 | 14 | // providers 15 | let twitter = new TwitterAuthProvider(); 16 | let facebook = new FacebookAuthProvider(); 17 | let github = new GithubAuthProvider(); 18 | let google = new GoogleAuthProvider(); 19 | 20 | // GOOGLE 21 | Shiny.addCustomMessageHandler('fireblaze-google-scope', (msg) => { 22 | google.addScope(msg); 23 | }); 24 | 25 | Shiny.addCustomMessageHandler('fireblaze-google-sign-in-popup', (msg) => { 26 | const auth = getAuth(); 27 | signInWithPopup(auth, google) 28 | .then((result) => { 29 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 30 | }).catch((error) => { 31 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 32 | }); 33 | }); 34 | 35 | Shiny.addCustomMessageHandler('fireblaze-google-sign-in-redirect', (msg) => { 36 | const auth = getAuth(); 37 | signInWithRedirect(auth, google); 38 | 39 | getRedirectResult(auth) 40 | .then((result) => { 41 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 42 | }).catch((error) => { 43 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 44 | }); 45 | }); 46 | 47 | // FACEBOOK 48 | Shiny.addCustomMessageHandler('fireblaze-facebook-scope', (msg) => { 49 | facebook.addScope(msg); 50 | }); 51 | 52 | Shiny.addCustomMessageHandler('fireblaze-facebook-sign-in-popup', (msg) => { 53 | const auth = getAuth(); 54 | signInWithPopup(auth, facebook) 55 | .then((result) => { 56 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 57 | }).catch((error) => { 58 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 59 | }); 60 | }); 61 | 62 | Shiny.addCustomMessageHandler('fireblaze-facebook-sign-in-redirect', (msg) => { 63 | const auth = getAuth(); 64 | signInWithRedirect(auth, facebook); 65 | 66 | getRedirectResult(auth) 67 | .then((result) => { 68 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 69 | }).catch((error) => { 70 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 71 | }); 72 | }); 73 | 74 | // GITHUB 75 | Shiny.addCustomMessageHandler('fireblaze-github-scope', (msg) => { 76 | github.addScope(msg); 77 | }); 78 | 79 | Shiny.addCustomMessageHandler('fireblaze-github-sign-in-popup', (msg) => { 80 | const auth = getAuth(); 81 | signInWithPopup(auth, github) 82 | .then(result => { 83 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 84 | }).catch(error => { 85 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 86 | }); 87 | }); 88 | 89 | Shiny.addCustomMessageHandler('fireblaze-github-sign-in-redirect', (msg) => { 90 | const auth = getAuth(); 91 | signInWithRedirect(auth, github); 92 | 93 | getRedirectResult(auth) 94 | .then(result => { 95 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 96 | }).catch(error => { 97 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 98 | }); 99 | }); 100 | 101 | // TWITTER 102 | Shiny.addCustomMessageHandler('fireblaze-twitter-scope', (msg) => { 103 | twitter.addScope(msg); 104 | }); 105 | 106 | Shiny.addCustomMessageHandler('fireblaze-twitter-sign-in-popup', (msg) => { 107 | const auth = getAuth(); 108 | signInWithPopup(auth, twitter) 109 | .then(result => { 110 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 111 | }).catch(error => { 112 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 113 | }); 114 | }); 115 | 116 | Shiny.addCustomMessageHandler('fireblaze-twitter-sign-in-redirect', msg => { 117 | const auth = getAuth(); 118 | signInWithRedirect(auth, twitter); 119 | 120 | getRedirectResult(auth) 121 | .then(result => { 122 | setInputValue('signed_up_user', {success: true, response: result}, msg.ns); 123 | }).catch(error => { 124 | setInputValue('signed_up_user', {success: false, response: error}, msg.ns); 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /srcjs/components/storage.js: -------------------------------------------------------------------------------- 1 | import 'shiny' 2 | import { 3 | getStorage, 4 | ref, 5 | uploadString, 6 | getDownloadURL, 7 | deleteObject, 8 | getMetadata, 9 | listAll 10 | } from "firebase/storage"; 11 | import { setInputValue2 } from '../utils.js'; 12 | 13 | let storage; 14 | 15 | export const handleStorage = (firebaseApp) => { 16 | let storageRef = ref(storage); 17 | 18 | Shiny.addCustomMessageHandler('fireblaze-storage-ref', function(msg) { 19 | if(!storage) 20 | storage = getStorage(firebaseApp); 21 | 22 | if(!msg.path){ 23 | storageRef = ref(storage); 24 | return ; 25 | } 26 | 27 | storageRef = ref(storage, msg.path); 28 | }); 29 | 30 | Shiny.addCustomMessageHandler('fireblaze-upload-file', function(msg) { 31 | uploadString(storageRef, msg.encoded, 'data_url') 32 | .then((snapshot) => { 33 | if(!msg.response) 34 | return; 35 | 36 | let data = { 37 | response: snapshot.metadata, 38 | success: true 39 | } 40 | 41 | setInputValue2(msg.response, data, msg.ns); 42 | }) 43 | .catch(error => { 44 | if(!msg.response) 45 | return; 46 | 47 | setInputValue2(msg.response, {success: false, response: error}, msg.ns); 48 | }); 49 | }); 50 | 51 | Shiny.addCustomMessageHandler('fireblaze-download-file', (msg) => { 52 | getDownloadURL(storageRef) 53 | .then((url) => { 54 | if(!msg.response) 55 | return; 56 | 57 | let data = { 58 | success: true, 59 | response: url, 60 | } 61 | 62 | setInputValue2(msg.response, data, msg.ns); 63 | }) 64 | .catch((error) => { 65 | if(!msg.response) 66 | return; 67 | 68 | setInputValue2(msg.response, {success: false, response: error}, msg.ns); 69 | }); 70 | }); 71 | 72 | Shiny.addCustomMessageHandler('fireblaze-delete-file', function(msg) { 73 | deleteObject(storageRef) 74 | .then(() => { 75 | if(!msg.response) 76 | return; 77 | 78 | setInputValue2(msg.response, {success: true, response: null}, msg.ns); 79 | }) 80 | .catch((error) => { 81 | if(!msg.response) 82 | return; 83 | 84 | setInputValue2(msg.response, {success: false, response: error}, msg.ns); 85 | }); 86 | }); 87 | 88 | Shiny.addCustomMessageHandler('fireblaze-get-metadata', function(msg) { 89 | getMetadata(storageRef) 90 | .then((metadata) => { 91 | if(!msg.response) 92 | return; 93 | 94 | setInputValue2(msg.response, {success: true, response: metadata}, msg.ns); 95 | }) 96 | .catch((error) => { 97 | if(!msg.response) 98 | return; 99 | 100 | setInputValue2(msg.response, {success: false, response: error}, msg.ns); 101 | }); 102 | }); 103 | 104 | Shiny.addCustomMessageHandler('fireblaze-list-all-files', function(msg) { 105 | listAll(storageRef) 106 | .then((res) => { 107 | setInputValue2(msg.response, {success: true, response: res.items}, msg.ns); 108 | }) 109 | .catch((error) => { 110 | if(!msg.response) 111 | return; 112 | 113 | setInputValue2(msg.response, {success: false, response: error}, msg.ns); 114 | }); 115 | }); 116 | } 117 | -------------------------------------------------------------------------------- /srcjs/config/entry_points.json: -------------------------------------------------------------------------------- 1 | { 2 | "core": { 3 | "import": "./srcjs/core.js", 4 | "dependOn": ["auth", "utilities"] 5 | }, 6 | "ui": { 7 | "import": "./srcjs/ui.js", 8 | "dependOn": ["auth", "utilities"] 9 | }, 10 | "analytics": { 11 | "import": "./srcjs/components/analytics.js", 12 | "dependOn": ["auth"] 13 | }, 14 | "email-link": { 15 | "import": "./srcjs/components/email-link.js", 16 | "dependOn": ["auth", "utilities"] 17 | }, 18 | "email-password": { 19 | "import": "./srcjs/components/email-password.js", 20 | "dependOn": ["auth", "utilities"] 21 | }, 22 | "oauth": { 23 | "import": "./srcjs/components/oauth.js", 24 | "dependOn": ["auth", "utilities"] 25 | }, 26 | "phone": { 27 | "import": "./srcjs/components/phone.js", 28 | "dependOn": ["auth", "utilities"] 29 | }, 30 | "social": { 31 | "import": "./srcjs/components/social.js", 32 | "dependOn": ["auth", "utilities"] 33 | }, 34 | "real-time": { 35 | "import": "./srcjs/components/real-time.js", 36 | "dependOn": "utilities" 37 | }, 38 | "utilities": { 39 | "import": "./srcjs/utils.js", 40 | "dependOn": "auth" 41 | }, 42 | "auth": "firebase/auth" 43 | } 44 | -------------------------------------------------------------------------------- /srcjs/config/externals.json: -------------------------------------------------------------------------------- 1 | { 2 | "shiny": "Shiny", 3 | "jquery": "jQuery" 4 | } 5 | -------------------------------------------------------------------------------- /srcjs/config/loaders.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "test": "\\.css$", 4 | "use": [ 5 | "style-loader", 6 | "css-loader" 7 | ] 8 | } 9 | ] 10 | -------------------------------------------------------------------------------- /srcjs/config/misc.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /srcjs/config/output_path.json: -------------------------------------------------------------------------------- 1 | "./inst/packer" 2 | -------------------------------------------------------------------------------- /srcjs/style.css: -------------------------------------------------------------------------------- 1 | .fireblaze__hidden{ 2 | opacity: 0; 3 | } -------------------------------------------------------------------------------- /srcjs/ui.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { 3 | getAuth, 4 | TwitterAuthProvider, 5 | GoogleAuthProvider, 6 | FacebookAuthProvider, 7 | GithubAuthProvider, 8 | EmailAuthProvider, 9 | PhoneAuthProvider, 10 | } from 'firebase/auth'; 11 | import * as firebaseui from 'firebaseui' 12 | import 'firebaseui/dist/firebaseui.css' 13 | 14 | // Convert sign in boolean from R to firebase strings 15 | const signinOpts = (opts) => { 16 | var signin = []; 17 | 18 | if(opts.microsoft) 19 | signin.push("microsoft.com"); 20 | 21 | if(opts.yahoo) 22 | signin.push("yahoo.com"); 23 | 24 | if(opts.apple) 25 | signin.push("apple.com"); 26 | 27 | if(opts.google) 28 | signin.push(GoogleAuthProvider.PROVIDER_ID); 29 | 30 | if(opts.facebook) 31 | signin.push(FacebookAuthProvider.PROVIDER_ID); 32 | 33 | if(opts.twitter) 34 | signin.push(TwitterAuthProvider.PROVIDER_ID); 35 | 36 | if(opts.github) 37 | signin.push(GithubAuthProvider.PROVIDER_ID); 38 | 39 | if(opts.email) 40 | signin.push(EmailAuthProvider.PROVIDER_ID); 41 | 42 | if(opts.email_link) 43 | signin.push({ 44 | provider: EmailAuthProvider.PROVIDER_ID, 45 | signInMethod: EmailAuthProvider.EMAIL_LINK_SIGN_IN_METHOD 46 | }); 47 | 48 | if(opts.phone) 49 | signin.push(PhoneAuthProvider.PROVIDER_ID); 50 | 51 | return signin; 52 | } 53 | 54 | const accountHelper = (x) => { 55 | if(x == false) 56 | return firebaseui.auth.CredentialHelper.NONE; 57 | 58 | return firebaseui.auth.CredentialHelper.GOOGLE_YOLO; 59 | } 60 | 61 | // Config init 62 | Shiny.addCustomMessageHandler('fireblaze-ui-config', (msg) => { 63 | const auth = getAuth(); 64 | 65 | if(!window.uiInitialised) { 66 | window.uiInitialised = true; 67 | window.ui = new firebaseui.auth.AuthUI(auth); 68 | } 69 | 70 | let providers = signinOpts(msg.providers); 71 | let helper = accountHelper(msg.account_helper); 72 | 73 | window.uiOpts = { 74 | callbacks: { 75 | signInSuccessWithAuthResult: (authResult, redirectUrl) => { 76 | setInputValue('signed_up_user', {success: true, response: auth.currentUser}, msg.ns); 77 | return(false); 78 | }, 79 | uiShown: () => { 80 | var loader = document.getElementById('loader'); 81 | 82 | if(loader) 83 | loader.style.display = 'none'; 84 | } 85 | }, 86 | credentialHelper: helper, 87 | signInFlow: msg.flow, 88 | signInOptions: providers, 89 | tosUrl: msg.tos_url, 90 | privacyPolicyUrl: msg.privacy_policy_url 91 | }; 92 | 93 | ui.start("#fireblaze-signin-ui", uiOpts); 94 | }); 95 | -------------------------------------------------------------------------------- /srcjs/utils.js: -------------------------------------------------------------------------------- 1 | import 'shiny'; 2 | import { 3 | browserSessionPersistence, 4 | browserLocalPersistence, 5 | inMemoryPersistence, 6 | getAuth, 7 | } from 'firebase/auth'; 8 | 9 | // Convert persistence option to firebase 10 | const persistenceOpts = (p) => { 11 | if(p == "none") 12 | return ; 13 | 14 | if(p == "memory") 15 | return inMemoryPersistence; 16 | 17 | if(p == "session") 18 | return browserSessionPersistence 19 | 20 | return browserLocalPersistence; 21 | } 22 | 23 | // toggle elements 24 | const showHideOnLogin = (method) => { 25 | var els = document.getElementsByClassName('fireblaze__requires__signin'); 26 | 27 | for(var i = 0; i < els.length; i++){ 28 | if(method == "hide") { 29 | els[i].classList.remove('fireblaze__hidden'); 30 | $(els[i]).hide(); 31 | } else if(method == "show") { 32 | els[i].classList.remove('fireblaze__hidden'); 33 | $(els[i]).show(); 34 | } 35 | } 36 | } 37 | 38 | // toggle elements 39 | const showHideOnLogout = (method) => { 40 | var els = document.getElementsByClassName('fireblaze__requires__signout'); 41 | 42 | for(var i = 0; i < els.length; i++){ 43 | if(method == "hide") { 44 | els[i].classList.remove('fireblaze__hidden'); 45 | $(els[i]).hide(); 46 | } else if(method == "show") { 47 | els[i].classList.remove('fireblaze__hidden'); 48 | $(els[i]).show(); 49 | } 50 | } 51 | } 52 | 53 | let prefix = 'fireblaze'; 54 | const setInputValue = (type, data, ns) => { 55 | if(!ns) 56 | ns = window.globalNs; 57 | 58 | Shiny.setInputValue( 59 | `${ns}${prefix}_${type}`, 60 | data 61 | ); 62 | } 63 | 64 | const setInputValue2 = (type, data, ns) => { 65 | if(!ns) 66 | ns = window.globalNs; 67 | 68 | Shiny.setInputValue( 69 | `${ns}${type}`, 70 | data 71 | ); 72 | } 73 | 74 | const setLanguageCode = (code) => { 75 | if(!code) 76 | return; 77 | 78 | const auth = getAuth(); 79 | 80 | if(code == 'browser'){ 81 | auth.languageCode = auth.useDeviceLanguage(); 82 | return ; 83 | } 84 | 85 | auth.languageCode = code; 86 | } 87 | 88 | export { 89 | persistenceOpts, 90 | showHideOnLogin, 91 | showHideOnLogout, 92 | setInputValue, 93 | setInputValue2, 94 | setLanguageCode, 95 | } -------------------------------------------------------------------------------- /vignettes/.gitignore: -------------------------------------------------------------------------------- 1 | *.html 2 | *.R 3 | -------------------------------------------------------------------------------- /vignettes/analytics.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Storage" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Storage} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | One might want to integrate the authentication with Google 18 | Analytics. 19 | 20 | You can conditionally log event with the `log_events` method as 21 | well as register custom user properties with `set_user_properties`. 22 | 23 | Note the caveats of toggling Google Analytics off in 24 | [the docs](reference/Analytics). 25 | 26 | ## Example 27 | 28 | ```r 29 | library(shiny) 30 | library(firebase) 31 | 32 | ui <- fluidPage( 33 | useFirebase(), 34 | firebaseUIContainer() 35 | ) 36 | 37 | server <- function(input, output){ 38 | f <- FirebaseUI$ 39 | new()$ 40 | set_providers( 41 | google = TRUE 42 | )$ 43 | launch() 44 | 45 | a <- Analytics$ 46 | new()$ 47 | launch() 48 | 49 | observeEvent(f$get_signed_in(), { 50 | f$req_sign_in() 51 | 52 | a$log_event('notification_received'); 53 | a$set_user_properties(level = "free") 54 | }) 55 | } 56 | 57 | shinyApp(ui, server) 58 | ``` 59 | -------------------------------------------------------------------------------- /vignettes/demo.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Demo" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{demo} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | The code for the [demo](https://shiny.john-coene.com/firebase) which provides 7 different sign in methods uses the `FirebaseUI` and is remarkably simple, see below. 18 | 19 | ```r 20 | library(shiny) 21 | library(firebase) 22 | 23 | ui <- fluidPage( 24 | useFirebase(), 25 | firebaseUIContainer(), 26 | reqSignin(actionButton("signout", "Sign out")), 27 | uiOutput("msg"), 28 | plotOutput("plot") 29 | ) 30 | 31 | server <- function(input, output){ 32 | f <- FirebaseUI$ 33 | new("session")$ 34 | set_providers( 35 | email = TRUE, 36 | yahoo = TRUE, 37 | google = TRUE, 38 | github = TRUE, 39 | twitter = TRUE, 40 | facebook = TRUE, 41 | microsoft = TRUE 42 | )$ 43 | launch() 44 | 45 | output$plot <- renderPlot({ 46 | f$req_sign_in() # require sign in 47 | plot(cars) 48 | }) 49 | 50 | output$msg <- renderUI({ 51 | f$req_sign_in() # require sign in 52 | 53 | user <- f$get_signed_in() # get logged in user info 54 | print(user) 55 | 56 | h4("Welcome,", user$response$displayName) 57 | }) 58 | 59 | observeEvent(input$signout, { 60 | f$sign_out() 61 | }) 62 | 63 | } 64 | 65 | shinyApp(ui, server) 66 | ``` 67 | -------------------------------------------------------------------------------- /vignettes/email-link.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Email Link" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Email Link} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | Creating an authentication flow using an email link is very similar to creating one with an email and password. The only difference is that we we don't observe for successful account creation but successful email sent with the `get_email_sent` method. 18 | 19 |
    20 |

    Redirect URL

    21 |

    Note that you have to specify the redirect URL in your config.

    22 |
    23 | 24 | Below we force shiny to run on port 3000 so we can reference the redirect URL in the `config` which is mandatory as the email link must obviously a link back to your application; `options(shiny.port = 3000)` is not necessary in prod. 25 | 26 | ```r 27 | library(shiny) 28 | library(firebase) 29 | 30 | options(shiny.port = 3000) 31 | 32 | ui <- fluidPage( 33 | useFirebase(), 34 | textInput("email", "Your email"), 35 | actionButton("submit", "Submit") 36 | ) 37 | 38 | server <- function(input, output){ 39 | 40 | f <- FirebaseEmailLink$ 41 | new()$ 42 | config(url = "http://127.0.0.1:3000") 43 | 44 | observeEvent(input$submit, { 45 | if(input$email == "") 46 | return() 47 | 48 | f$send_email(input$email) 49 | }) 50 | 51 | observeEvent(f$get_email_sent(), { 52 | sent <- f$get_email_sent() 53 | 54 | if(sent$success) 55 | showNotification("Email sent", type = "message") 56 | }) 57 | 58 | observeEvent(f$get_email_verification(), { 59 | print(f$get_email_verification()) 60 | }) 61 | 62 | } 63 | 64 | shinyApp(ui, server) 65 | ``` -------------------------------------------------------------------------------- /vignettes/firebase_email_password.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/firebase_email_password.gif -------------------------------------------------------------------------------- /vignettes/firebase_redirect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/firebase_redirect.png -------------------------------------------------------------------------------- /vignettes/firebase_yahoo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/firebase_yahoo.png -------------------------------------------------------------------------------- /vignettes/fireblaze_facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_facebook.png -------------------------------------------------------------------------------- /vignettes/fireblaze_github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_github.png -------------------------------------------------------------------------------- /vignettes/fireblaze_github_popup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_github_popup.png -------------------------------------------------------------------------------- /vignettes/fireblaze_google.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_google.png -------------------------------------------------------------------------------- /vignettes/fireblaze_home.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_home.png -------------------------------------------------------------------------------- /vignettes/fireblaze_project.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_project.png -------------------------------------------------------------------------------- /vignettes/fireblaze_signin_method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_signin_method.png -------------------------------------------------------------------------------- /vignettes/fireblaze_social.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_social.gif -------------------------------------------------------------------------------- /vignettes/fireblaze_step_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_step_1.png -------------------------------------------------------------------------------- /vignettes/fireblaze_step_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_step_2.png -------------------------------------------------------------------------------- /vignettes/fireblaze_users.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblaze_users.png -------------------------------------------------------------------------------- /vignettes/fireblazer_project_setup1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblazer_project_setup1.png -------------------------------------------------------------------------------- /vignettes/fireblazer_step_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/fireblazer_step_3.png -------------------------------------------------------------------------------- /vignettes/flow.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "flow" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{flow} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | ## flow 18 | 19 | There are two different authentication "flows:" redirect and popup (default). The former redirect the user to another tab while the latter opens up in a popup window. 20 | 21 | ## Usage 22 | 23 | Finally, we currently provide a sign-in method but we do not do anything with it. Generally, we will need to block of hide all or the parts of the app that requires sign-in. There are two ways to go about this, 1) an insecure way in which we hide the UI elements before the user signs in but the user could, with basic CSS, reveal those elements before signing in. 2) A more secure way in which one waits for the user to sign in to render certain elements. 24 | 25 | The first happens UI-side and is very easy to implement, the second happens server-side. 26 | 27 | ### UI 28 | 29 |
    30 |

    Important

    31 |

    This method is convenient but not secure use the "server" method instead.

    32 |
    33 | 34 | Rather straightforward but might not work for all elements. Use `reqSignin` to wrap UI elements that require sign in. Below we wrap some text and a plot, only signed in users can see them. There is also the corollary, `reqSignout` which will only show when the user is not signed in. 35 | 36 | ```r 37 | library(shiny) 38 | library(firebase) 39 | 40 | ui <- fluidPage( 41 | useFirebase(), # import dependencies 42 | firebaseUIContainer(), 43 | reqSignout( 44 | h1("Please sign in") 45 | ), 46 | reqSignin( 47 | h4("VIP plot below"), 48 | plotOutput("plot") 49 | ) 50 | ) 51 | 52 | server <- function(input, output){ 53 | f <- FirebaseUI$ 54 | new()$ # instantiate 55 | set_providers( # define providers 56 | email = TRUE, 57 | google = TRUE 58 | )$ 59 | launch() # launch 60 | 61 | output$plot <- renderPlot({ 62 | plot(cars) 63 | }) 64 | } 65 | 66 | shinyApp(ui, server) 67 | ``` 68 | 69 | ### Server 70 | 71 | Server-side you can either manually check that the user has signed in with the `is_signed_in` method, which returns `TRUE` if a user is signed in and `FALSE` otherwise. Or you can use the convenient `req_sign_in` in your outputs make sign in required for them. 72 | 73 |
    74 |

    Important

    75 |

    You are strongly advised to use this method.

    76 |
    77 | 78 | ```r 79 | library(shiny) 80 | library(firebase) 81 | 82 | ui <- fluidPage( 83 | useFirebase(), # import dependencies 84 | firebaseUIContainer(), 85 | uiOutput("msg"), 86 | reqSignin(h4("VIP plot below")), # hide from UI 87 | plotOutput("plot") 88 | ) 89 | 90 | server <- function(input, output){ 91 | f <- FirebaseUI$ 92 | new()$ # instantiate 93 | set_providers( # define providers 94 | email = TRUE, 95 | google = TRUE 96 | )$ 97 | launch() # launch 98 | 99 | output$msg <- renderUI({ 100 | f$req_sign_out() 101 | h2("Please sign in") 102 | }) 103 | 104 | output$plot <- renderPlot({ 105 | f$req_sign_in() # require sign in 106 | plot(cars) 107 | }) 108 | } 109 | 110 | shinyApp(ui, server) 111 | ``` 112 | -------------------------------------------------------------------------------- /vignettes/github_oauth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/github_oauth.png -------------------------------------------------------------------------------- /vignettes/manage.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Manage Users" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{Manage Users} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | 16 | user <- list(success = TRUE, response = list(uid = "xxx", 17 | displayName = NULL, photoURL = NULL, email = "john@opifex.org", 18 | emailVerified = FALSE, phoneNumber = NULL, isAnonymous = FALSE, 19 | tenantId = NULL, providerData = list(list(uid = "john@opifex.org", 20 | displayName = NULL, photoURL = NULL, email = "john@opifex.org", 21 | phoneNumber = NULL, providerId = "password")), apiKey = "xxx", 22 | appName = "[DEFAULT]", authDomain = "fireblaze-r-package.firebaseapp.com", 23 | stsTokenManager = list(apiKey = "xxx", 24 | refreshToken = "xxx", 25 | accessToken = "xxx", 26 | expirationTime = 1631729634000), redirectEventId = NULL, 27 | lastLoginAt = "1631726033959", createdAt = "1631639076093", 28 | multiFactor = list(enrolledFactors = list()))) 29 | ``` 30 | 31 | ## Sign in 32 | 33 | You can always access the signed in user with the `get_signed_in` method. This returns a list of length 2: 34 | 35 | 1. `signed_in`: boolean 36 | 2. `user`: a list (`NULL` if signed out) 37 | 38 | The user object returned looks like. 39 | 40 | ```{r, echo = FALSE} 41 | print(user) 42 | ``` 43 | 44 | Note this is technically like a Shiny input and behaves as such. Therefore the snippet below will work. Note that it will be triggered on load. 45 | 46 | ```r 47 | # initialise 48 | f <- FireblazeUI$new()$launch() 49 | 50 | observeEvent(f$get_signed_in(), { 51 | # do somethind 52 | }) 53 | ``` 54 | 55 | However one should probably only rely on the `get_signed_in` to retrieve information about the logged in user, the methods `is_signed_in` and `req_sign_in` should be used in observers instead. The first returns `TRUE` if the user is signed in. The second, `req_sign_in` is a convenience method which essentially does `req(f$is_signed_in)` which allows "marking" outputs and observers that require sign in. 56 | 57 | ## Sign out 58 | 59 | A single method is shared across all authentication methods, simply call `sign_out` method. 60 | 61 | ## Re-auth 62 | 63 | Two sensitive operations, deleting an account, and changing a password (only application to email & password method), might require that you re-authenticate the user. These operations being dangerous they will fail if the user has been signed in for a long time and you will have to first re-authenticate them using their current password. 64 | 65 | ```r 66 | f <- FirebaseEmailPassword$new() 67 | 68 | # upon clicking a button 69 | observeEvent(input$reAuth, { 70 | # pass the freshly entered user password 71 | f$re_authenticate(input$reAuthPassword) 72 | }) 73 | 74 | # check if reauth successful 75 | observeEvent(f$get_re_authenticated(), { 76 | reauth <- f$get_re_authenticated() 77 | 78 | # TRUE if successful 79 | print(reauth$success) 80 | }) 81 | ``` 82 | 83 | ## Delete 84 | 85 | Simply use the `delete_user` method and observe the result with the `get_delete_user` method. This will likely required re-authentication. 86 | 87 | ## Email & Password 88 | 89 | Signing in users with email and password may require some work, at times, to manage them. You might want to send them an email verification link, allow them to change or reset their password. 90 | 91 | You can freely send a verification email with the `send_verification_email` and receive the response to it with `get_verification_email`. 92 | -------------------------------------------------------------------------------- /vignettes/oauth-providers.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Oauth Providers" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{oauth-providers} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | You might have already browsed the [guide on social sign in](social.html). They are in fact convenience wrapper to the more general "Oauth providers" class. It works in a very similar fashion and can even prove more convenient. 18 | 19 | ## R Package 20 | 21 | First, instantiate the authentication from `FirebaseOauthProviders`, then define the provider you want to use with `set_provider`, finally `launch` whenever you want. 22 | 23 | Below we have the authentication launch at the click of a button. We provide Microsoft by simply setting `microsoft.com` as provider. All that is needed to change to say Yahoo! is to change the provider to `yahoo.com` for instance. 24 | 25 | ```r 26 | library(shiny) 27 | library(firebase) 28 | 29 | ui <- fluidPage( 30 | useFirebase(), 31 | actionButton("signin", "Sign in with Microsoft", icon = icon("microsoft")), 32 | plotOutput("plot") 33 | ) 34 | 35 | server <- function(input, output, session){ 36 | f <- FirebaseOauthProviders$ 37 | new()$ 38 | set_provider("microsoft.com") 39 | 40 | observeEvent(input$signin, { 41 | f$launch() 42 | }) 43 | 44 | output$plot <- renderPlot({ 45 | f$req_sign_in() 46 | plot(cars) 47 | }) 48 | 49 | } 50 | 51 | shinyApp(ui, server) 52 | ``` 53 | 54 | ## Console Setup 55 | 56 | The R-side of things is rather easy so here we briefly explain how to integrate those oauth providers with the Firebase console. 57 | 58 | ### Yahoo 59 | 60 | For Yahoo it is fairly straightforward. Open you console under "Sign-in method" tab and enable Yahoo! as show below. 61 | 62 | ![](firebase_yahoo.png) 63 | 64 | To get the necessary app ID and app secret visit [this link](https://developer.yahoo.com/apps/create/) and create an app 65 | 66 |
    67 |

    Important

    68 |

    Make sure you enter the "Redirect URI(s)" given to you by Firebase which resembles `https://my-application.firebaseapp.com/__/auth/handler` and tick the `OpenID Connect Permissions` at the bottom.

    69 |
    70 | 71 | On the resulting screen copy the app ID and secret to your Firebase console. 72 | 73 | ### Microsoft 74 | 75 | Authenticating via Microsoft is handled by Microsoft Azure, create a free account if you do not have one the: 76 | 77 | 1. Visit [the portal](https://portal.azure.com/) 78 | 2. Search and select "Azure Active Directory" 79 | 3. In the left sidebar under "Manage" select "App registrations" 80 | 4. Then click New registrations 81 | 5. Under "Redirect URI" select "Web" and place the redirect URL given by Firebase 82 | 6. Once created, on the "overview" screen copy the "Application (client) ID" to Firebase 83 | 7. The visit "Certificates & secrets" in the sidebar 84 | 8. Create a "New client secret" and copy it to Firebase 85 | 86 | Once this done give Microsoft 2 minutes to sync before trying the authentication. 87 | -------------------------------------------------------------------------------- /vignettes/phone.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "phone" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{phone} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | In the latest version you can also allow signing in with 18 | mobile phone numbers. 19 | 20 |
    21 |

    Enable

    22 |

    23 | Remember to enable this sign in method in your Firebase 24 | console. 25 |

    26 |
    27 | 28 | ## 1. Verify 29 | 30 | First, collect the user's phone number __and the recaptcha.__ 31 | To collect the capta, simply place `recaptchaUI` where you want 32 | it to display. Note that it will apply only after you run 33 | the `verfify` method (see below). 34 | 35 | ## 2. Confirm 36 | 37 | Once the `verify` method has run the user receives a confirmation 38 | code that you must also capture and pass to `confirm` to confirm 39 | the authentication. The user is then automatically logged in. 40 | 41 | ## Example 42 | 43 | This is an overly simple, ugly example, but fully-functioning. 44 | 45 | ```r 46 | library(shiny) 47 | library(firebase) 48 | 49 | ui <- fluidPage( 50 | useFirebase(), 51 | textInput( 52 | "number", 53 | "Number" 54 | ), 55 | actionButton("verify", "Verify"), 56 | recaptchaUI(), 57 | textInput("code", "Code"), 58 | actionButton("confirm", "Confirm") 59 | ) 60 | 61 | server <- function(input, output, session) { 62 | f <- FirebasePhone$new() 63 | 64 | observeEvent(input$verify, { 65 | f$verify(input$number) 66 | }) 67 | 68 | observeEvent(f$get_verification(), { 69 | print(f$get_verification()) 70 | }) 71 | 72 | observeEvent(input$confirm, { 73 | f$confirm(input$code) 74 | }) 75 | 76 | observeEvent(f$get_confirmation(), { 77 | print(f$get_confirmation()) 78 | }) 79 | } 80 | 81 | shinyApp(ui, server) 82 | ``` -------------------------------------------------------------------------------- /vignettes/state-persistence.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | title: "state-persistence" 3 | output: rmarkdown::html_vignette 4 | vignette: > 5 | %\VignetteIndexEntry{state-persistence} 6 | %\VignetteEngine{knitr::rmarkdown} 7 | %\VignetteEncoding{UTF-8} 8 | --- 9 | 10 | ```{r, include = FALSE} 11 | knitr::opts_chunk$set( 12 | collapse = TRUE, 13 | comment = "#>" 14 | ) 15 | ``` 16 | 17 | You can specify how the Authentication state persists. This includes the ability to specify whether a signed in user should be indefinitely persisted until explicit sign out, cleared when the window is closed or cleared on page reload. 18 | 19 | In Firebase, there are three options. 20 | 21 | 1. `none` (default) - Indicates that the state will only be stored in memory and will be cleared when the window or activity is refreshed. 22 | 2. `local`- Indicates that the state will be persisted even when the browser window is closed or the activity is destroyed in React Native. An explicit sign out is needed to clear that state. Note that Firebase Auth web sessions are single host origin and will be persisted for a single domain only. 23 | 3. `session` - Indicates that the state will only persist in the current session or tab, and will be cleared when the tab or window in which the user authenticated is closed. Applies only to web apps. 24 | 25 | In the R package, you can modify state persistence with the `persistence` argument when instantiating the class with `new`. 26 | 27 | ```r 28 | library(shiny) 29 | library(fireblaze) 30 | 31 | # define signin 32 | signin <- modalDialog( 33 | title = "Login", 34 | actionButton("google", "Google", icon = icon("google"), class = "btn-danger"), 35 | actionButton("github", "Github", icon = icon("github")), 36 | footer = NULL 37 | ) 38 | 39 | ui <- fluidPage( 40 | useFirebase(), 41 | uiOutput("msg") 42 | ) 43 | 44 | server <- function(input, output) { 45 | showModal(signin) 46 | 47 | f <- FirebaseSocial$new(persistence = "local") 48 | 49 | observeEvent(input$google, { 50 | f$launch_google() 51 | }) 52 | 53 | observeEvent(input$github, { 54 | f$launch_github() 55 | }) 56 | 57 | output$msg <- renderUI({ 58 | f$req_sign_in() 59 | 60 | h3("Welcome!") 61 | }) 62 | } 63 | 64 | shinyApp(ui, server) 65 | ``` -------------------------------------------------------------------------------- /vignettes/ui_simple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/ui_simple.png -------------------------------------------------------------------------------- /vignettes/yahoo_create.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JohnCoene/firebase/01bf3e4f1186aa1bcb6c106eac1b55fc713d9d49/vignettes/yahoo_create.png -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | 4 | // defaults 5 | var outputPath = [], 6 | entryPoints = [], 7 | externals = [], 8 | misc = [], 9 | loaders = []; 10 | 11 | var outputPathFile = './srcjs/config/output_path.json', 12 | entryPointsFile = './srcjs/config/entry_points.json', 13 | externalsFile = './srcjs/config/externals.json', 14 | miscFile = './srcjs/config/misc.json', 15 | loadersFile = './srcjs/config/loaders.json'; 16 | 17 | // Read config files 18 | if(fs.existsSync(outputPathFile)){ 19 | outputPath = fs.readFileSync(outputPathFile, 'utf8'); 20 | } 21 | 22 | if(fs.existsSync(entryPointsFile)){ 23 | entryPoints = fs.readFileSync(entryPointsFile, 'utf8'); 24 | } 25 | 26 | if(fs.existsSync(externalsFile)){ 27 | externals = fs.readFileSync(externalsFile, 'utf8'); 28 | } 29 | 30 | if(fs.existsSync(miscFile)){ 31 | misc = fs.readFileSync(miscFile, 'utf8'); 32 | } 33 | 34 | if(fs.existsSync(loadersFile)){ 35 | loaders = fs.readFileSync(loadersFile, 'utf8'); 36 | } 37 | 38 | if(fs.existsSync(loadersFile)){ 39 | loaders = fs.readFileSync(loadersFile, 'utf8'); 40 | } 41 | 42 | // parse 43 | loaders = JSON.parse(loaders); 44 | misc = JSON.parse(misc); 45 | externals = JSON.parse(externals); 46 | entryPoints = JSON.parse(entryPoints); 47 | 48 | // parse regex 49 | loaders.forEach((loader) => { 50 | loader.test = RegExp(loader.test); 51 | return(loader); 52 | }) 53 | 54 | // placeholder for plugins 55 | var plugins = [ 56 | ]; 57 | 58 | // define options 59 | var options = { 60 | entry: entryPoints, 61 | output: { 62 | filename: '[name].js', 63 | path: path.resolve(__dirname, JSON.parse(outputPath)), 64 | }, 65 | externals: externals, 66 | module: { 67 | rules: loaders 68 | }, 69 | resolve: { 70 | extensions: ['.tsx', '.ts', '.js'], 71 | }, 72 | plugins: plugins, 73 | optimization: { 74 | runtimeChunk: 'single', 75 | } 76 | }; 77 | 78 | // add misc 79 | if(misc.resolve) 80 | options.resolve = misc.resolve; 81 | 82 | // export 83 | module.exports = options; 84 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common, { 5 | mode: 'development', 6 | devtool: 'inline-source-map' 7 | }); 8 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge'); 2 | const common = require('./webpack.common.js'); 3 | 4 | module.exports = merge(common, { 5 | mode: 'production', 6 | }); 7 | --------------------------------------------------------------------------------