From 9edfd8be907c5c5463ef54ed4b9c7e501b0baa90 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Wed, 22 May 2024 10:48:38 +0200 Subject: [PATCH 01/17] feat: Add react-native modules for PouchDB `react-native-quick-sqlite` is enforced to version `8.0.6` in order to be compatible with RN0.72 Related article: https://dev.to/craftzdog/a-performant-way-to-use-pouchdb7-on-react-native-in-2022-24ej --- README.md | 1 + __tests__/jest.config.js | 2 +- __tests__/jestSetupFile.js | 2 + android/build.gradle | 2 + babel.config.js | 1 + ios/Podfile.lock | 21 + package.json | 11 + yarn.lock | 820 +++++++++++++++++++++++++++++++++++-- 8 files changed, 831 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index ef4d1ee0a..ce6578585 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ This notably includes the possiblity to run client-side konnectors, to get your - [iOS only] Install XCode - [Android only] Install Android Studio (or Android SDK) - [Android only] Java 11 +- [Android only] Install NDK (21.4.7075529) and CMake (3.10.2) from Android Studio's SDK Manager - [Android only] Copy the Android's `debug.keystore` from Cozy's password-store into `android/app/debug.keystore` - Run `pass show app-amirale/Certificates/debug.keystore > android/app/debug.keystore` - If you don't have access to Cozy's password-store, just generate a new `debug.keystore` file diff --git a/__tests__/jest.config.js b/__tests__/jest.config.js index 0d6117ffd..f94580a2e 100644 --- a/__tests__/jest.config.js +++ b/__tests__/jest.config.js @@ -13,7 +13,7 @@ const config = { '/__tests__/transformer/imageTransformer.js' }, transformIgnorePatterns: [ - 'node_modules/(?!((jest-)?react-native(-.*)?|@react-native(-community)?|p-timeout?|p-wait-for?|@notifee?)|@fengweichong/react-native-gzip?/)' + 'node_modules/(?!((jest-)?react-native(-.*)?|@react-native(-community)?|p-timeout?|p-wait-for?|@notifee?)|@fengweichong/react-native-gzip|@craftzdog/*?/)' ], rootDir: '../' } diff --git a/__tests__/jestSetupFile.js b/__tests__/jestSetupFile.js index d6bd11cdb..a546def4a 100644 --- a/__tests__/jestSetupFile.js +++ b/__tests__/jestSetupFile.js @@ -127,3 +127,5 @@ jest.mock('../src/core/tools/env', () => ({ devlog: jest.fn(), shouldDisableAutolock: jest.fn().mockReturnValue(false) })) + +jest.mock('react-native-quick-websql', () => ({})) diff --git a/android/build.gradle b/android/build.gradle index c79cfd0aa..34a6e1424 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -10,6 +10,8 @@ buildscript { googlePlayServicesLocationVersion = "20.0.0" DocumentScanner_compileSdkVersion = 34 DocumentScanner_targetSdkVersion = 34 + QuickBase64_compileSdkVersion = 34 + QuickBase64_targetSdkVersion = 34 kotlinVersion = '1.8.0' // react-native-receive-sharing-intent requires a global kotlin version else the build fails // We use NDK 23 which has both M1 support and is the side-by-side NDK version from AGP. ndkVersion = "23.1.7779620" diff --git a/babel.config.js b/babel.config.js index c9699505e..e8190b359 100644 --- a/babel.config.js +++ b/babel.config.js @@ -8,6 +8,7 @@ module.exports = { root: ['./'], alias: { '^/(.+)': './src/\\1', + 'pouchdb-collate': '@craftzdog/pouchdb-collate-react-native', '@cozy/minilog': 'cozy-minilog' }, extensions: [ diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 506f6ed80..0df044c93 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -502,6 +502,8 @@ PODS: - React-Core - react-native-flipper (0.146.1): - React-Core + - react-native-get-random-values (1.11.0): + - React-Core - react-native-gzip (2.0.0): - NVHTarGzip - React @@ -514,6 +516,13 @@ PODS: - React-Core - react-native-print (0.11.0): - React-Core + - react-native-quick-base64 (2.1.2): + - RCT-Folly (= 2021.07.22.00) + - React-Core + - react-native-quick-sqlite (8.0.6): + - React + - React-callinvoker + - React-Core - react-native-receive-sharing-intent (2.2.1): - React-Core - react-native-restart (0.0.27): @@ -764,11 +773,14 @@ DEPENDENCIES: - "react-native-cookies (from `../node_modules/@react-native-cookies/cookies`)" - react-native-document-scanner-plugin (from `../node_modules/react-native-document-scanner-plugin`) - react-native-flipper (from `../node_modules/react-native-flipper`) + - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - "react-native-gzip (from `../node_modules/@fengweichong/react-native-gzip`)" - react-native-idle-timer (from `../node_modules/react-native-idle-timer`) - react-native-mlkit-ocr (from `../node_modules/react-native-mlkit-ocr`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-print (from `../node_modules/react-native-print`) + - react-native-quick-base64 (from `../node_modules/react-native-quick-base64`) + - react-native-quick-sqlite (from `../node_modules/react-native-quick-sqlite`) - "react-native-receive-sharing-intent (from `../node_modules/@mythologi/react-native-receive-sharing-intent`)" - react-native-restart (from `../node_modules/react-native-restart`) - react-native-safe-area-context (from `../node_modules/react-native-safe-area-context`) @@ -919,6 +931,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native-document-scanner-plugin" react-native-flipper: :path: "../node_modules/react-native-flipper" + react-native-get-random-values: + :path: "../node_modules/react-native-get-random-values" react-native-gzip: :path: "../node_modules/@fengweichong/react-native-gzip" react-native-idle-timer: @@ -929,6 +943,10 @@ EXTERNAL SOURCES: :path: "../node_modules/@react-native-community/netinfo" react-native-print: :path: "../node_modules/react-native-print" + react-native-quick-base64: + :path: "../node_modules/react-native-quick-base64" + react-native-quick-sqlite: + :path: "../node_modules/react-native-quick-sqlite" react-native-receive-sharing-intent: :path: "../node_modules/@mythologi/react-native-receive-sharing-intent" react-native-restart: @@ -1089,11 +1107,14 @@ SPEC CHECKSUMS: react-native-cookies: f54fcded06bb0cda05c11d86788020b43528a26c react-native-document-scanner-plugin: df5b82df67ff612262c40c26ef2c8239c5af5c55 react-native-flipper: 4bfe0a324e663f1ae2f76ad0da75673de6895efe + react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06 react-native-gzip: 5ffb84bf191c7cd135338eca748317bc466d41a1 react-native-idle-timer: f1920a59fe776340d004ff9de13c4a6eedcc8807 react-native-mlkit-ocr: 72cdbde86f8d29cba26cf9fa0a1865fe45c8f8d6 react-native-netinfo: 48c5f79a84fbc3ba1d28a8b0d04adeda72885fa8 react-native-print: f704aef52d931bfce6d1d84351dbb5232d7ecb89 + react-native-quick-base64: 42a805dcf2ae4f38c4d2c7e7a3c7dd936e5d248a + react-native-quick-sqlite: e0e23b749382a85e4b57146f753de737a6c3a9e1 react-native-receive-sharing-intent: 0c21b8e80f629a73341f2566ce9b99df8124bb10 react-native-restart: 7595693413fe3ca15893702f2c8306c62a708162 react-native-safe-area-context: 39c2d8be3328df5d437ac1700f4f3a4f75716acc diff --git a/package.json b/package.json index 18cb0890e..479e29977 100644 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "storybook:update": "sb-rn-get-stories" }, "dependencies": { + "@craftzdog/pouchdb-collate-react-native": "^7.3.0", "@fengweichong/react-native-gzip": "github:cozy/react-native-gzip#1.1.0", "@mythologi/react-native-receive-sharing-intent": "2.2.1", "@notifee/react-native": "^7.8.0", @@ -62,6 +63,7 @@ "cozy-logger": "^1.10.0", "cozy-minilog": "3.3.1", "date-fns": "2.29.3", + "events": "^3.3.0", "html-entities": "^2.3.3", "i18next": "23.7.16", "i18next-intervalplural-postprocessor": "3.0.0", @@ -73,6 +75,11 @@ "patch-package": "^8.0.0", "post-me": "^0.4.5", "postinstall-postinstall": "^2.1.0", + "pouchdb-adapter-http": "^8.0.1", + "pouchdb-adapter-react-native-sqlite": "^3.0.1", + "pouchdb-core": "^8.0.1", + "pouchdb-mapreduce": "^8.0.1", + "pouchdb-replication": "^8.0.1", "react": "18.2.0", "react-dom": "18.2.0", "react-i18next": "14.0.0", @@ -91,6 +98,7 @@ "react-native-flipper": "^0.146.1", "react-native-fs": "^2.20.0", "react-native-gesture-handler": "1.10.3", + "react-native-get-random-values": "^1.11.0", "react-native-google-play-integrity": "github:cozy/react-native-google-play-integrity#1.0.1", "react-native-iap": "^12.11.0", "react-native-idle-timer": "^2.2.1", @@ -104,6 +112,9 @@ "react-native-permissions": "^3.9.3", "react-native-play-install-referrer": "^1.1.8", "react-native-print": "0.11.0", + "react-native-quick-base64": "2.1.2", + "react-native-quick-sqlite": "8.0.6", + "react-native-quick-websql": "^0.3.0", "react-native-restart": "^0.0.27", "react-native-safe-area-context": "^4.5.0", "react-native-screens": "3.32.0", diff --git a/yarn.lock b/yarn.lock index 448f5d235..544d8d0d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2846,6 +2846,24 @@ dependencies: microee "0.0.6" +"@craftzdog/pouchdb-adapter-websql-core@^7.2.3": + version "7.2.3" + resolved "https://registry.yarnpkg.com/@craftzdog/pouchdb-adapter-websql-core/-/pouchdb-adapter-websql-core-7.2.3.tgz#01ebaaf71dd7b844c66c58ae8cc460ec3aeb8009" + integrity sha512-bXt9rOwMgUEyQhcr8KWDAhOA1J7XfI//mrlEg0O3KQo81Ck5i6oxWU+BYpw9wC2pnKmhboRkIwFAz9QQbHefrg== + dependencies: + pouchdb-adapter-utils "^7.2.2" + pouchdb-binary-utils "^7.2.2" + pouchdb-collections "^7.2.2" + pouchdb-errors "^7.2.2" + pouchdb-json "^7.2.2" + pouchdb-merge "^7.2.2" + pouchdb-utils "^7.2.2" + +"@craftzdog/pouchdb-collate-react-native@^7.3.0": + version "7.3.0" + resolved "https://registry.yarnpkg.com/@craftzdog/pouchdb-collate-react-native/-/pouchdb-collate-react-native-7.3.0.tgz#4bc25c8d11f1f270f5c7de4a1a4c4819b04e4147" + integrity sha512-ZC1fBSt7lBy8A3bGLsZVuDf/f3NWTOj+x0ygYUMWPCZPtzKfbRWdirv/pPKKxsO09Aw2EGuo94v51UOAIQkpRQ== + "@csstools/convert-colors@^1.4.0": version "1.4.0" resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" @@ -3012,6 +3030,11 @@ version "2.0.0" resolved "https://codeload.github.com/cozy/react-native-gzip/tar.gz/41178cf223fe3c866dfa6ede78a881461de066fd" +"@gar/promisify@^1.0.1": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" + integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== + "@hapi/address@2.x.x": version "2.1.4" resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5" @@ -3926,6 +3949,14 @@ resolved "https://registry.yarnpkg.com/@notifee/react-native/-/react-native-7.8.0.tgz#2990883753990f3585aa0cb5becc5cbdbcd87a43" integrity sha512-sx8h62U4FrR4pqlbN1rkgPsdamDt9Tad0zgfO6VtP6rNJq/78k8nxUnh0xIX3WPDcCV8KAzdYCE7+UNvhF1CpQ== +"@npmcli/fs@^1.0.0": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.1.1.tgz#72f719fe935e687c56a4faecf3c03d06ba593257" + integrity sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ== + dependencies: + "@gar/promisify" "^1.0.1" + semver "^7.3.5" + "@npmcli/move-file@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" @@ -6102,7 +6133,12 @@ abab@^2.0.3, abab@^2.0.5: resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== -abort-controller@^3.0.0: +abbrev@1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== + +abort-controller@3.0.0, abort-controller@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== @@ -6178,13 +6214,20 @@ adjust-sourcemap-loader@3.0.0: loader-utils "^2.0.0" regex-parser "^2.2.11" -agent-base@6: +agent-base@6, agent-base@^6.0.2: version "6.0.2" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" +agentkeepalive@^4.1.3: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -6385,6 +6428,14 @@ are-we-there-yet@^2.0.0: delegates "^1.0.0" readable-stream "^3.6.0" +are-we-there-yet@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz#679df222b278c64f2cdba1175cdc00b0d96164bd" + integrity sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg== + dependencies: + delegates "^1.0.0" + readable-stream "^3.6.0" + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -6397,6 +6448,11 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +argsarray@0.0.1, argsarray@^0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/argsarray/-/argsarray-0.0.1.tgz#6e7207b4ecdb39b0af88303fa5ae22bda8df61cb" + integrity sha512-u96dg2GcAKtpTrBdDoFIM7PjcBA+6rSP0OR94MOReNRyUECL6MtQt5XXmRr4qrftYaef9+l5hcpO5te7sML1Cg== + aria-query@^4.2.2: version "4.2.2" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-4.2.2.tgz#0d2ca6c9aceb56b8977e9fed6aed7e15bbd2f83b" @@ -7181,7 +7237,7 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" -bl@^4.1.0: +bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== @@ -7425,6 +7481,11 @@ buffer-equal@0.0.1: resolved "https://registry.yarnpkg.com/buffer-equal/-/buffer-equal-0.0.1.tgz#91bc74b11ea405bc916bc6aa908faafa5b4aac4b" integrity sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA== +buffer-from@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -7526,6 +7587,30 @@ cacache@^15.0.5: tar "^6.0.2" unique-filename "^1.1.1" +cacache@^15.2.0: + version "15.3.0" + resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== + dependencies: + "@npmcli/fs" "^1.0.0" + "@npmcli/move-file" "^1.0.1" + chownr "^2.0.0" + fs-minipass "^2.0.0" + glob "^7.1.4" + infer-owner "^1.0.4" + lru-cache "^6.0.0" + minipass "^3.1.1" + minipass-collect "^1.0.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.2" + mkdirp "^1.0.3" + p-map "^4.0.0" + promise-inflight "^1.0.1" + rimraf "^3.0.2" + ssri "^8.0.1" + tar "^6.0.2" + unique-filename "^1.1.1" + cache-base@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" @@ -7812,6 +7897,11 @@ cliui@^8.0.1: strip-ansi "^6.0.1" wrap-ansi "^7.0.0" +clone-buffer@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-buffer/-/clone-buffer-1.0.0.tgz#e3e25b207ac4e701af721e2cb5a16792cac3dc58" + integrity sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g== + clone-deep@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713" @@ -7903,7 +7993,7 @@ color-string@^1.9.0: color-name "^1.0.0" simple-swizzle "^0.2.2" -color-support@^1.1.2: +color-support@^1.1.2, color-support@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.3.tgz#93834379a1cc9a0c61f82f52f0d04322251bd5a2" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== @@ -8683,7 +8773,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -8717,6 +8807,13 @@ decode-uri-component@^0.2.2: resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== +decompress-response@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" + integrity sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ== + dependencies: + mimic-response "^3.1.0" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -8744,6 +8841,11 @@ deep-equal@^1.0.1: object-keys "^1.1.1" regexp.prototype.flags "^1.2.0" +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -8889,6 +8991,11 @@ destroy@~1.0.4: resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= +detect-libc@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -9207,7 +9314,14 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= -end-of-stream@^1.0.0, end-of-stream@^1.1.0: +encoding@^0.1.12: + version "0.1.13" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== + dependencies: + iconv-lite "^0.6.2" + +end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== @@ -9258,11 +9372,21 @@ entities@^4.2.0: resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== +env-paths@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" + integrity sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A== + envinfo@^7.7.2, envinfo@^7.7.3: version "7.8.1" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== +err-code@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== + errno@^0.1.3, errno@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f" @@ -10023,7 +10147,7 @@ eventemitter3@^4.0.0: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== -events@^3.0.0, events@^3.2.0: +events@^3.0.0, events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== @@ -10114,6 +10238,11 @@ expand-brackets@^2.1.4: snapdragon "^0.8.1" to-regex "^3.0.1" +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + expect@^26.6.0, expect@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" @@ -10209,6 +10338,11 @@ extglob@^2.0.4: snapdragon "^0.8.1" to-regex "^3.0.1" +fast-base64-decode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-base64-decode/-/fast-base64-decode-1.0.0.tgz#b434a0dd7d92b12b43f26819300d2dafb83ee418" + integrity sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q== + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -10308,6 +10442,13 @@ fbjs@^3.0.0: setimmediate "^1.0.5" ua-parser-js "^0.7.18" +fetch-cookie@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/fetch-cookie/-/fetch-cookie-0.11.0.tgz#e046d2abadd0ded5804ce7e2cae06d4331c15407" + integrity sha512-BQm7iZLFhMWFy5CZ/162sAGjBfdNWb7a8LEqqnzsHFhxT/X/SVj/z2t2nu3aJvjlbQkrAlTUApplPRjWyH4mhA== + dependencies: + tough-cookie "^2.3.3 || ^3.0.1 || ^4.0.0" + figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" @@ -10597,6 +10738,11 @@ from2@^2.1.0: inherits "^2.0.1" readable-stream "^2.0.0" +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -10748,6 +10894,20 @@ gauge@^3.0.0: strip-ansi "^6.0.1" wide-align "^1.1.2" +gauge@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-4.0.4.tgz#52ff0652f2bbf607a989793d53b751bef2328dce" + integrity sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg== + dependencies: + aproba "^1.0.3 || ^2.0.0" + color-support "^1.1.3" + console-control-strings "^1.1.0" + has-unicode "^2.0.1" + signal-exit "^3.0.7" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wide-align "^1.1.5" + gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -10841,6 +11001,11 @@ gifwrap@^0.9.2: image-q "^4.0.0" omggif "^1.0.10" +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== + glob-parent@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" @@ -11005,6 +11170,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== +graceful-fs@^4.2.6: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + grapheme-splitter@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz#9cf3a665c6247479896834af35cf1dbb4400767e" @@ -11295,6 +11465,11 @@ htmlparser2@^3.10.1: inherits "^2.0.1" readable-stream "^3.1.1" +http-cache-semantics@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" + integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== + http-deceiver@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" @@ -11388,6 +11563,13 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + i18next-intervalplural-postprocessor@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/i18next-intervalplural-postprocessor/-/i18next-intervalplural-postprocessor-3.0.0.tgz#35580abdaff5e838c44c22740a7178063b7bdd0b" @@ -11407,6 +11589,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-utils@^4.0.0, icss-utils@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467" @@ -11455,6 +11644,11 @@ image-size@^1.0.2: dependencies: queue "6.0.2" +immediate@3.3.0, immediate@^3.2.2: + version "3.3.0" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.3.0.tgz#1aef225517836bcdf7f2a2de2600c79ff0269266" + integrity sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" @@ -11559,7 +11753,7 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.5: +ini@^1.3.5, ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== @@ -11612,6 +11806,14 @@ invariant@2.2.4, invariant@^2.2.4: dependencies: loose-envify "^1.0.0" +ip-address@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-9.0.5.tgz#117a960819b08780c3bd1f14ef3c1cc1d3f3ea5a" + integrity sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g== + dependencies: + jsbn "1.1.0" + sprintf-js "^1.1.3" + ip-regex@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" @@ -11900,6 +12102,11 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-lambda@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== + is-map@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" @@ -13157,6 +13364,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + jsc-android@^250231.0.0: version "250231.0.0" resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250231.0.0.tgz#91720f8df382a108872fa4b3f558f33ba5e95262" @@ -13668,6 +13880,28 @@ make-error@1.x: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +make-fetch-happen@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== + dependencies: + agentkeepalive "^4.1.3" + cacache "^15.2.0" + http-cache-semantics "^4.1.0" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-lambda "^1.0.1" + lru-cache "^6.0.0" + minipass "^3.1.3" + minipass-collect "^1.0.2" + minipass-fetch "^1.3.2" + minipass-flush "^1.0.5" + minipass-pipeline "^1.2.4" + negotiator "^0.6.2" + promise-retry "^2.0.1" + socks-proxy-agent "^6.0.0" + ssri "^8.0.0" + makeerror@1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" @@ -14133,6 +14367,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +mimic-response@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9" + integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== + min-document@^2.19.0: version "2.19.0" resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" @@ -14191,7 +14430,7 @@ minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== -minimist@^1.2.6: +minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -14203,6 +14442,17 @@ minipass-collect@^1.0.2: dependencies: minipass "^3.0.0" +minipass-fetch@^1.3.2: + version "1.4.1" + resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== + dependencies: + minipass "^3.1.0" + minipass-sized "^1.0.3" + minizlib "^2.0.0" + optionalDependencies: + encoding "^0.1.12" + minipass-flush@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" @@ -14210,13 +14460,20 @@ minipass-flush@^1.0.5: dependencies: minipass "^3.0.0" -minipass-pipeline@^1.2.2: +minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== dependencies: minipass "^3.0.0" +minipass-sized@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== + dependencies: + minipass "^3.0.0" + minipass@^3.0.0, minipass@^3.1.1: version "3.1.3" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" @@ -14224,14 +14481,19 @@ minipass@^3.0.0, minipass@^3.1.1: dependencies: yallist "^4.0.0" -minipass@^3.3.5: +minipass@^3.1.0, minipass@^3.1.3, minipass@^3.3.5: version "3.3.6" resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.3.6.tgz#7bba384db3a1520d18c9c0e5251c3444e95dd94a" integrity sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw== dependencies: yallist "^4.0.0" -minizlib@^2.1.1: +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + +minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== @@ -14271,6 +14533,11 @@ mixin-object@^2.0.1: for-in "^0.1.3" is-extendable "^0.1.1" +mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" + integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== + mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: version "0.5.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" @@ -14310,7 +14577,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -14355,6 +14622,11 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +napi-build-utils@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" + integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== + native-url@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" @@ -14377,6 +14649,11 @@ negotiator@0.6.2: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +negotiator@^0.6.2: + version "0.6.3" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + neo-async@^2.5.0, neo-async@^2.6.1, neo-async@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" @@ -14415,11 +14692,23 @@ nock@13.2.9: lodash "^4.17.21" propagate "^2.0.0" +node-abi@^3.3.0: + version "3.65.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-3.65.0.tgz#ca92d559388e1e9cab1680a18c1a18757cdac9d3" + integrity sha512-ThjYBfoDNr08AWx6hGaRbfPwxKV9kVzAzOzlLKbk2CuqXE2xnCh+cbAGnwM3t8Lq4v9rUB7VfondlkBckcJrVA== + dependencies: + semver "^7.3.5" + node-abort-controller@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/node-abort-controller/-/node-abort-controller-3.1.1.tgz#a94377e964a9a37ac3976d848cb5c765833b8548" integrity sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ== +node-addon-api@^7.0.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.1.tgz#1aba6693b0f255258a049d621329329322aad558" + integrity sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ== + node-dir@^0.1.17: version "0.1.17" resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" @@ -14432,6 +14721,13 @@ node-fetch@2.6.1, node-fetch@^2.2.0, node-fetch@^2.6.0: resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== +node-fetch@2.6.7, node-fetch@^2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" + integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== + dependencies: + whatwg-url "^5.0.0" + node-fetch@^2.6.1: version "2.6.9" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.9.tgz#7c7f744b5cc6eb5fd404e0c7a9fec630a55657e6" @@ -14439,18 +14735,27 @@ node-fetch@^2.6.1: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.7: - version "2.6.7" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" - integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== - dependencies: - whatwg-url "^5.0.0" - node-forge@^0.10.0: version "0.10.0" resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3" integrity sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA== +node-gyp@8.x: + version "8.4.1" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-8.4.1.tgz#3d49308fc31f768180957d6b5746845fbd429937" + integrity sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w== + dependencies: + env-paths "^2.2.0" + glob "^7.1.4" + graceful-fs "^4.2.6" + make-fetch-happen "^9.1.0" + nopt "^5.0.0" + npmlog "^6.0.0" + rimraf "^3.0.2" + semver "^7.3.5" + tar "^6.1.2" + which "^2.0.2" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -14533,6 +14838,18 @@ node-stream-zip@^1.9.1: resolved "https://registry.yarnpkg.com/node-stream-zip/-/node-stream-zip-1.13.4.tgz#baafc329ffb9e27de84b6882d74e9f2cbe77e2a5" integrity sha512-M2nPvnSWFFH+fgLIRZDqmhshmuzXcr+ce9BsHQX/30pXR+cEz/USMYmx9ZAFYy837W2QoDoNzhFtbZhfzaMk9A== +noop-fn@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/noop-fn/-/noop-fn-1.0.0.tgz#5f33d47f13d2150df93e0cb036699e982f78ffbf" + integrity sha512-pQ8vODlgXt2e7A3mIbFDlizkr46r75V+BJxVAyat8Jl7YmI513gG5cfyRL0FedKraoZ+VAouI1h4/IWpus5pcQ== + +nopt@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== + dependencies: + abbrev "1" + normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -14599,6 +14916,16 @@ npmlog@^5.0.1: gauge "^3.0.0" set-blocking "^2.0.0" +npmlog@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-6.0.2.tgz#c8166017a42f2dea92d6453168dd865186a70830" + integrity sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg== + dependencies: + are-we-there-yet "^3.0.0" + console-control-strings "^1.1.0" + gauge "^4.0.3" + set-blocking "^2.0.0" + nth-check@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" @@ -16074,6 +16401,251 @@ postinstall-postinstall@^2.1.0: resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== +pouchdb-abstract-mapreduce@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-8.0.1.tgz#f45aa1424fdd272a76ceb5722a53b38c10a0ca81" + integrity sha512-BxJRHdfiC8gID8h4DPS0Xy6wsa2VBHRHMv9hsm0BhGTWTqS4k8ivItVSeU2dMoXiTBYp+7SerYmovUQNGSX1GA== + dependencies: + pouchdb-binary-utils "8.0.1" + pouchdb-collate "8.0.1" + pouchdb-collections "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-fetch "8.0.1" + pouchdb-mapreduce-utils "8.0.1" + pouchdb-md5 "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-adapter-http@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-adapter-http/-/pouchdb-adapter-http-8.0.1.tgz#d44b8e2299602fcfb1bf456eae43256b39b35316" + integrity sha512-krs5T8QVsswIyDRQHZCBBMF0l7HKQkxZwEigUTVvhq6kuHuqUheLGv18sPiVvmXlpdZwRl/d1432MkG72ywqIw== + dependencies: + pouchdb-binary-utils "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-fetch "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-adapter-react-native-sqlite@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-adapter-react-native-sqlite/-/pouchdb-adapter-react-native-sqlite-3.0.1.tgz#f20e8e23389ecc57607668104aca018b2d9b7c05" + integrity sha512-oODToI/j0Q/C3VbJMR/sStdjrXwcANFzpwaWdMWrQK95V0NrbtTHlOKycHW+6or1asu2giSjwbvJYMpL/nmi3g== + dependencies: + "@craftzdog/pouchdb-adapter-websql-core" "^7.2.3" + +pouchdb-adapter-utils@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-adapter-utils/-/pouchdb-adapter-utils-7.3.1.tgz#7237cb597f8d337057df15d4859bfe3c881d8832" + integrity sha512-uKLG6dClwTs/sLIJ4WkLAi9wlnDBpOnfyhpeAgOjlOGN/XLz5nKHrA4UJRnURDyc+uv79S9r/Unc4hVpmbSPUw== + dependencies: + pouchdb-binary-utils "7.3.1" + pouchdb-collections "7.3.1" + pouchdb-errors "7.3.1" + pouchdb-md5 "7.3.1" + pouchdb-merge "7.3.1" + pouchdb-utils "7.3.1" + +pouchdb-binary-utils@7.3.1, pouchdb-binary-utils@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-7.3.1.tgz#eea22d9a5f880fcd95062476f4f5484cdf61496f" + integrity sha512-crZJNfAEOnUoRk977Qtmk4cxEv6sNKllQ6vDDKgQrQLFjMUXma35EHzNyIJr1s76J77Q4sqKQAmxz9Y40yHGtw== + dependencies: + buffer-from "1.1.2" + +pouchdb-binary-utils@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-binary-utils/-/pouchdb-binary-utils-8.0.1.tgz#aa77248b9c0ad2a68f75f8f7cf2b594fe3dbd559" + integrity sha512-WsuR/S0aoUlcA0Alt99czkXsfuXWcrYXAcvGiTW02zawVXOafCnb/qHjA09TUaV0oy5HeHmYaNnDckoOUqspeA== + dependencies: + buffer-from "1.1.2" + +pouchdb-changes-filter@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-changes-filter/-/pouchdb-changes-filter-8.0.1.tgz#691b71b209dda12e950672ce44de2680606a98e4" + integrity sha512-UKgH6YRA9PnvIGHb0FuDEEqeTewgHugbbBt5vpVo0QmbWKxNiau/JiTC9mY5Hj9l7ghaIUpO0TFG95a6RXWsQA== + dependencies: + pouchdb-errors "8.0.1" + pouchdb-selector-core "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-checkpointer@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-checkpointer/-/pouchdb-checkpointer-8.0.1.tgz#beb4f922b8dbd59f851fe95c7fe540d69f870bf8" + integrity sha512-zWIFEpQqY/7Fx75VkWtxbMYlL5gzPN9SUYqFCCUPPIThEM3evREI/4u4V0ayNkd9Ma3OGyItsj0D1ibBghWenA== + dependencies: + pouchdb-collate "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-collate@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-8.0.1.tgz#14b6ad9330d2831fd8ef135de680060366502a1b" + integrity sha512-DTuNz1UJjBTGZMUlWS1klSE1rPsmHy8IIDie3MFH1ZTz/C+SwGgGwkiAyUDv/n00D18EMLgXq5mu+r7L6K1BwQ== + +pouchdb-collections@7.3.1, pouchdb-collections@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-7.3.1.tgz#4f1819cf4dd6936a422c29f7fa26a9b5dca428f5" + integrity sha512-yUyDqR+OJmtwgExOSJegpBJXDLAEC84TWnbAYycyh+DZoA51Yw0+XVQF5Vh8Ii90/Ut2xo88fmrmp0t6kqom8w== + +pouchdb-collections@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-8.0.1.tgz#d6a31ab3a917fa5da49d46a804c04761a0e19655" + integrity sha512-TlkQ2GGHJApJgL0b7bJMQcwX6eMfVenLeoK9mqHfC2fJssui+HWJJ5LYKHOWan11SeB90BQVFbO6rHN6CJQeDg== + +pouchdb-core@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-core/-/pouchdb-core-8.0.1.tgz#3066f4f24dd90e669da0ea3f67205cbc1e3bfa71" + integrity sha512-Qkcmh3eoMHiKUma5Y/rH0Z7kjxXrr6p54j/WOH+TZ/RlJAchmdVY1TRfqay5CoK+8Ka0m8eibP+wD1DKZKJbDg== + dependencies: + pouchdb-changes-filter "8.0.1" + pouchdb-collections "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-fetch "8.0.1" + pouchdb-merge "8.0.1" + pouchdb-utils "8.0.1" + uuid "8.3.2" + +pouchdb-errors@7.3.1, pouchdb-errors@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-7.3.1.tgz#78be36721e2edc446fac158a236a9218c7bcdb14" + integrity sha512-Zktz4gnXEUcZcty8FmyvtYUYsHskoST05m6H5/E2gg/0mCfEXq/XeyyLkZHaZmqD0ZPS9yNmASB1VaFWEKEaDw== + dependencies: + inherits "2.0.4" + +pouchdb-errors@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-8.0.1.tgz#d57afd57e07490d8d0b4ef19c10bfc85dbf27ae5" + integrity sha512-H+ZsQxcG/JV3Tn29gnM6c9+lRPCN91ZYOkoIICsLjVRYgOTzN1AvNUD/G5JCB+81aI/u3fxZec0LEaZh6g6NHA== + +pouchdb-fetch@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-fetch/-/pouchdb-fetch-8.0.1.tgz#30a27a45eb24c20f346a04d906ba82bca5a3a525" + integrity sha512-Px5HLT8MxqTujc8bpPRKoouznDTJa9XBGqCbhl95q6rhjWRfwZEvXjV92z0B5BALAM6D6avMyG0DjuNfUWnMuA== + dependencies: + abort-controller "3.0.0" + fetch-cookie "0.11.0" + node-fetch "2.6.7" + +pouchdb-generate-replication-id@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-generate-replication-id/-/pouchdb-generate-replication-id-8.0.1.tgz#2c473bdb7f5e5bc08337b3042841f186bf3d0b2b" + integrity sha512-MxctzPSF9c3w0tPUPCR4Ihs3+N4751kFidgFnYVLRLZbWy3BNuY8GXjXQojLke7d2lMqQyuu4kKyCdOZ/kT8gQ== + dependencies: + pouchdb-collate "8.0.1" + pouchdb-md5 "8.0.1" + +pouchdb-json@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-json/-/pouchdb-json-7.3.1.tgz#a80a3060aa2914959e4dca7a4e2022ab20c7119a" + integrity sha512-AyOKsmc85/GtHjMZyEacqzja8qLVfycS1hh1oskR+Bm5PIITX52Fb8zyi0hEetV6VC0yuGbn0RqiLjJxQePeqQ== + dependencies: + vuvuzela "1.0.3" + +pouchdb-mapreduce-utils@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-8.0.1.tgz#a8acb1542aaf63a007b60f7a281dbbb94b49fcab" + integrity sha512-asZcFLy1DA3oe5CeXIRCpfVrBHaHRvSb3Tc/LPD1dZDDtpEkeCuXGtJm+praN0jl41jTBEm0uMdD/YI0J5ZFXw== + dependencies: + pouchdb-collections "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-mapreduce@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-mapreduce/-/pouchdb-mapreduce-8.0.1.tgz#f796d7436228572f94179d43ae75a19b5bf89f7a" + integrity sha512-cS36ANhxD8J8cWhqV9OYE5HFU0+jIli2Ow+FV6xKAcFnSogcLPAawGJMsg0mCyhaBqlCNOp1eMWMWz8jk/TStg== + dependencies: + pouchdb-abstract-mapreduce "8.0.1" + pouchdb-mapreduce-utils "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-md5@7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-7.3.1.tgz#70fae44f9d27eb4c6a8e7106156b4593d31c1762" + integrity sha512-aDV8ui/mprnL3xmt0gT/81DFtTtJiKyn+OxIAbwKPMfz/rDFdPYvF0BmDC9QxMMzGfkV+JJUjU6at0PPs2mRLg== + dependencies: + pouchdb-binary-utils "7.3.1" + spark-md5 "3.0.2" + +pouchdb-md5@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-md5/-/pouchdb-md5-8.0.1.tgz#5a3df4939102423727e0594c2a9bb91b82a444ed" + integrity sha512-shVcs/K/iilrcAhDEERpLIrGm/cnDVsXiocOzs7kycJEuBqYnLD9nj58VwWDcum26wfa8T9cznvEGE1jlYVNPQ== + dependencies: + pouchdb-binary-utils "8.0.1" + spark-md5 "3.0.2" + +pouchdb-merge@7.3.1, pouchdb-merge@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-7.3.1.tgz#97aae682d7d8499b62b6ce234dcb9527c7bf6f02" + integrity sha512-FeK3r35mKimokf2PQ2tUI523QWyZ4lYZ0Yd75FfSch/SPY6wIokz5XBZZ6PHdu5aOJsEKzoLUxr8CpSg9DhcAw== + +pouchdb-merge@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-merge/-/pouchdb-merge-8.0.1.tgz#7f948298274908546d89050c26ec52ac2f3cd252" + integrity sha512-79dw6+K7js2+/kt9u4hKOkGCnz+ov0+yft2k21n6M+ylFEQyMKuWHEZRoFWr72o1vxwjhIXhUM1PB2PIdxIh0Q== + dependencies: + pouchdb-utils "8.0.1" + +pouchdb-replication@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-replication/-/pouchdb-replication-8.0.1.tgz#31593356ce95564cc340f3e35ac3b02bdf2769d2" + integrity sha512-BIWhJsw2si3+HX3U5ElHJ6mv/cp5mA3pHynJYhufmbUe2vdLf4cpc7G5FG/ElMFEs0aoweGXPhFTqfqjykSZQA== + dependencies: + pouchdb-checkpointer "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-generate-replication-id "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-selector-core@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-8.0.1.tgz#d52119b79bd34b69c27f4596dbb9e16373bbd92e" + integrity sha512-dHWsnR+mLGyfVld1vSHJI1xKTwS1xk1G2dggjfXfUrLehI+wysjTUOwiSNytyPzG6DpT+o86wyUpwzPwsDCLBw== + dependencies: + pouchdb-collate "8.0.1" + pouchdb-utils "8.0.1" + +pouchdb-utils@7.3.1, pouchdb-utils@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-7.3.1.tgz#d25f0a034427f388ba5ae37d9ae3fbed210e8720" + integrity sha512-R3hHBo1zTdTu/NFs3iqkcaQAPwhIH0gMIdfVKd5lbDYlmP26rCG5pdS+v7NuoSSFLJ4xxnaGV+Gjf4duYsJ8wQ== + dependencies: + argsarray "0.0.1" + clone-buffer "1.0.0" + immediate "3.3.0" + inherits "2.0.4" + pouchdb-collections "7.3.1" + pouchdb-errors "7.3.1" + pouchdb-md5 "7.3.1" + uuid "8.3.2" + +pouchdb-utils@8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/pouchdb-utils/-/pouchdb-utils-8.0.1.tgz#3fb0c9fe00f52e4d8404278a609f277c1c155b70" + integrity sha512-pWgxdk9EHVWJmjQoEvTe+ZlPXyjcuQ/vgLITN+RjGwcYhoQYUE1M0PksQd2dUP3V8lGS4+wrg9lEM/qSJPYcpw== + dependencies: + clone-buffer "1.0.0" + immediate "3.3.0" + pouchdb-collections "8.0.1" + pouchdb-errors "8.0.1" + pouchdb-md5 "8.0.1" + uuid "8.3.2" + +prebuild-install@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056" + integrity sha512-UnNke3IQb6sgarcZIDU3gbMeTp/9SSU1DAIkil7PrqG1vZlBtY5msYccSKSHDqa3hNg436IXK+SNImReuA1wEQ== + dependencies: + detect-libc "^2.0.0" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.3" + mkdirp-classic "^0.5.3" + napi-build-utils "^1.0.1" + node-abi "^3.3.0" + pump "^3.0.0" + rc "^1.2.7" + simple-get "^4.0.0" + tar-fs "^2.0.0" + tunnel-agent "^0.6.0" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" @@ -16172,6 +16744,14 @@ promise-inflight@^1.0.1: resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= +promise-retry@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== + dependencies: + err-code "^2.0.2" + retry "^0.12.0" + promise.allsettled@^1.0.0: version "1.0.7" resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.7.tgz#b9dd51e9cffe496243f5271515652c468865f2d8" @@ -16450,6 +17030,16 @@ raw-body@2.4.0: iconv-lite "0.4.24" unpipe "1.0.0" +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + react-app-polyfill@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/react-app-polyfill/-/react-app-polyfill-2.0.0.tgz#a0bea50f078b8a082970a9d853dc34b6dcc6a3cf" @@ -16641,6 +17231,13 @@ react-native-gesture-handler@1.10.3: invariant "^2.2.4" prop-types "^15.7.2" +react-native-get-random-values@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/react-native-get-random-values/-/react-native-get-random-values-1.11.0.tgz#1ca70d1271f4b08af92958803b89dccbda78728d" + integrity sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ== + dependencies: + fast-base64-decode "^1.0.0" + "react-native-google-play-integrity@github:cozy/react-native-google-play-integrity#1.0.1": version "1.0.1" resolved "https://codeload.github.com/cozy/react-native-google-play-integrity/tar.gz/ad182ed9e5c83a38e7cd5ee55f1fc06b5ca93e11" @@ -16723,6 +17320,25 @@ react-native-print@0.11.0: resolved "https://registry.yarnpkg.com/react-native-print/-/react-native-print-0.11.0.tgz#3dc69fb05552f0c5da5be0dd345a93e1604621d1" integrity sha512-hFDzb9dVJVT8c3VHNNWgkPfLF3Jfyw0WVJ3o7wUmSMmi5hJx6b++veNJ3J95d3lW3Y0sZUpGbn9+yzXrLANnJQ== +react-native-quick-base64@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/react-native-quick-base64/-/react-native-quick-base64-2.1.2.tgz#062b09b165c1530095fe99b94544c948318dbe99" + integrity sha512-xghaXpWdB0ji8OwYyo0fWezRroNxiNFCNFpGUIyE7+qc4gA/IGWnysIG5L0MbdoORv8FkTKUvfd6yCUN5R2VFA== + dependencies: + base64-js "^1.5.1" + +react-native-quick-sqlite@8.0.6: + version "8.0.6" + resolved "https://registry.yarnpkg.com/react-native-quick-sqlite/-/react-native-quick-sqlite-8.0.6.tgz#ac1b662efe5641bc51eb7a8ee8ffac8af29532c4" + integrity sha512-XtwXnfZ1a6zRzAHoWFyVJsP3p8etx3/xww1oFKGdiOSj054PdYIeup9A53rtQ6ENyg+aqSKOgmxoN/PetulGOQ== + +react-native-quick-websql@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/react-native-quick-websql/-/react-native-quick-websql-0.3.0.tgz#acb53da8263b36fc5644e5faa06e2e069233a104" + integrity sha512-ysP+9HzEfiq0ex9plgmKddLz42RGPCiGsTNqnah3K8FCyKzYWRyVd8SboIdOiSFpB3vulwc/qMOBLVdmgjsaIw== + dependencies: + websql "^2.0.3" + react-native-restart@^0.0.27: version "0.0.27" resolved "https://registry.yarnpkg.com/react-native-restart/-/react-native-restart-0.0.27.tgz#43aa8210312c9dfa5ec7bd4b2f35238ad7972b19" @@ -17552,7 +18168,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -17912,6 +18528,20 @@ signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +simple-concat@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" + integrity sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q== + +simple-get@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-4.0.1.tgz#4a39db549287c979d352112fa03fd99fd6bc3543" + integrity sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA== + dependencies: + decompress-response "^6.0.0" + once "^1.3.1" + simple-concat "^1.0.0" + simple-plist@^1.1.0: version "1.3.1" resolved "https://registry.yarnpkg.com/simple-plist/-/simple-plist-1.3.1.tgz#16e1d8f62c6c9b691b8383127663d834112fb017" @@ -17961,6 +18591,11 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" +smart-buffer@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" + integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -18012,6 +18647,23 @@ sockjs@^0.3.21: uuid "^3.4.0" websocket-driver "^0.7.4" +socks-proxy-agent@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" + integrity sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ== + dependencies: + agent-base "^6.0.2" + debug "^4.3.3" + socks "^2.6.2" + +socks@^2.6.2: + version "2.8.3" + resolved "https://registry.yarnpkg.com/socks/-/socks-2.8.3.tgz#1ebd0f09c52ba95a09750afe3f3f9f724a800cb5" + integrity sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw== + dependencies: + ip-address "^9.0.5" + smart-buffer "^4.2.0" + sort-keys@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" @@ -18089,6 +18741,11 @@ sourcemap-codec@^1.4.4: resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4" integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA== +spark-md5@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/spark-md5/-/spark-md5-3.0.2.tgz#7952c4a30784347abcee73268e473b9c0167e3fc" + integrity sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw== + spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -18150,11 +18807,28 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +sprintf-js@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" + integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= +sqlite3@^5.0.2: + version "5.1.7" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" + integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== + dependencies: + bindings "^1.5.0" + node-addon-api "^7.0.0" + prebuild-install "^7.1.1" + tar "^6.1.11" + optionalDependencies: + node-gyp "8.x" + ssri@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" @@ -18162,7 +18836,7 @@ ssri@^6.0.1: dependencies: figgy-pudding "^3.5.1" -ssri@^8.0.1: +ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== @@ -18529,6 +19203,11 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== + strnum@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" @@ -18692,6 +19371,27 @@ tapable@^2.1.1, tapable@^2.2.0: resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b" integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw== +tar-fs@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784" + integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng== + dependencies: + chownr "^1.1.1" + mkdirp-classic "^0.5.2" + pump "^3.0.0" + tar-stream "^2.1.4" + +tar-stream@^2.1.4: + version "2.2.0" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + tar@^6.0.2: version "6.1.0" resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83" @@ -18704,6 +19404,18 @@ tar@^6.0.2: mkdirp "^1.0.3" yallist "^4.0.0" +tar@^6.1.11, tar@^6.1.2: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== + dependencies: + chownr "^2.0.0" + fs-minipass "^2.0.0" + minipass "^5.0.0" + minizlib "^2.1.1" + mkdirp "^1.0.3" + yallist "^4.0.0" + telejson@^6.0.8: version "6.0.8" resolved "https://registry.yarnpkg.com/telejson/-/telejson-6.0.8.tgz#1c432db7e7a9212c1fbd941c3e5174ec385148f7" @@ -18866,6 +19578,11 @@ timsort@^0.3.0: resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= +tiny-queue@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tiny-queue/-/tiny-queue-0.2.1.tgz#25a67f2c6e253b2ca941977b5ef7442ef97a6046" + integrity sha512-EijGsv7kzd9I9g0ByCl6h42BWNGUZrlCSejfrb3AKeHC33SGbASu1VDf5O3rRiiUOhAC9CHdZxFPbZu0HmR70A== + tinycolor2@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" @@ -18943,6 +19660,16 @@ token-types@^4.1.1: "@tokenizer/token" "^0.3.0" ieee754 "^1.2.1" +"tough-cookie@^2.3.3 || ^3.0.1 || ^4.0.0": + version "4.1.4" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.4.tgz#945f1461b45b5a8c76821c33ea49c3ac192c1b36" + integrity sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.2.0" + url-parse "^1.5.3" + tough-cookie@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" @@ -19040,6 +19767,13 @@ tty-browserify@0.0.0: resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -19265,6 +19999,11 @@ universalify@^0.1.0, universalify@^0.1.2: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -19338,6 +20077,14 @@ url-parse@^1.4.3, url-parse@^1.5.1: querystringify "^2.1.1" requires-port "^1.0.0" +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + url-search-params-polyfill@^8.0.0: version "8.1.1" resolved "https://registry.yarnpkg.com/url-search-params-polyfill/-/url-search-params-polyfill-8.1.1.tgz#9e69e4dba300a71ae7ad3cead62c7717fd99329f" @@ -19441,6 +20188,11 @@ uuid-browser@^3.1.0: resolved "https://registry.yarnpkg.com/uuid-browser/-/uuid-browser-3.1.0.tgz#0f05a40aef74f9e5951e20efbf44b11871e56410" integrity sha512-dsNgbLaTrd6l3MMxTtouOCFw4CBFc/3a+GgYA2YyrJvyQ1u6q4pcu3ktLoUZ/VN/Aw9WsauazbgsgdfVWgAKQg== +uuid@8.3.2, uuid@^8.3.0: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + uuid@^3.3.2, uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" @@ -19451,11 +20203,6 @@ uuid@^7.0.3: resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== -uuid@^8.3.0: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - v8-compile-cache@^2.0.3, v8-compile-cache@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" @@ -19512,6 +20259,11 @@ void-elements@3.1.0: resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" integrity sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w== +vuvuzela@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/vuvuzela/-/vuvuzela-1.0.3.tgz#3be145e58271c73ca55279dd851f12a682114b0b" + integrity sha512-Tm7jR1xTzBbPW+6y1tknKiEhz04Wf/1iZkcTJjSFcpNko43+dFW6+OOeQe9taJIug3NdfUAjFKgUSyQrIKaDvQ== + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -19856,6 +20608,18 @@ websocket-extensions@>=0.1.1: resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== +websql@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/websql/-/websql-2.0.3.tgz#5a747dc01fd1bc27633f64a2971d410500f70568" + integrity sha512-bSYpuhQ4ODKrWLb6S+9BG2T4AMqHLjCQA9r8UWCapPvTZYXoembz0O14Ga4EAfJuO1wkmFcJjgU/6tzvPfGbmA== + dependencies: + argsarray "^0.0.1" + immediate "^3.2.2" + noop-fn "^1.0.0" + tiny-queue "^0.2.1" + optionalDependencies: + sqlite3 "^5.0.2" + whatwg-encoding@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" @@ -19952,7 +20716,7 @@ which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -wide-align@^1.1.2: +wide-align@^1.1.2, wide-align@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.5.tgz#df1d4c206854369ecf3c9a4898f1b23fbd9d15d3" integrity sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg== From 6f9d3ec8795aa37539cbefc982dac508d76a0100 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 28 May 2024 20:16:14 +0200 Subject: [PATCH 02/17] feat: Configure PouchDB to run on the project Related article: https://dev.to/craftzdog/a-performant-way-to-use-pouchdb7-on-react-native-in-2022-24ej --- __tests__/jestSetupFile.js | 1 + src/index.js | 2 ++ src/pouchdb/pouchdb.js | 16 ++++++++++++++++ src/pouchdb/shim.js | 6 ++++++ 4 files changed, 25 insertions(+) create mode 100644 src/pouchdb/pouchdb.js create mode 100644 src/pouchdb/shim.js diff --git a/__tests__/jestSetupFile.js b/__tests__/jestSetupFile.js index a546def4a..1b7f0e0e9 100644 --- a/__tests__/jestSetupFile.js +++ b/__tests__/jestSetupFile.js @@ -128,4 +128,5 @@ jest.mock('../src/core/tools/env', () => ({ shouldDisableAutolock: jest.fn().mockReturnValue(false) })) +jest.mock('../src/pouchdb/pouchdb', () => ({})) jest.mock('react-native-quick-websql', () => ({})) diff --git a/src/index.js b/src/index.js index bdea29771..93ea42c09 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,5 @@ +import '/pouchdb/shim' + import { AppRegistry } from 'react-native' import App from './App' diff --git a/src/pouchdb/pouchdb.js b/src/pouchdb/pouchdb.js new file mode 100644 index 000000000..c7ae74dae --- /dev/null +++ b/src/pouchdb/pouchdb.js @@ -0,0 +1,16 @@ +// eslint-disable-next-line import/order +import 'react-native-get-random-values' + +import HttpPouch from 'pouchdb-adapter-http' +import SQLiteAdapterFactory from 'pouchdb-adapter-react-native-sqlite' +import PouchDB from 'pouchdb-core' +import mapreduce from 'pouchdb-mapreduce' +import replication from 'pouchdb-replication' +import WebSQLite from 'react-native-quick-websql' + +const SQLiteAdapter = SQLiteAdapterFactory(WebSQLite) + +export default PouchDB.plugin(HttpPouch) + .plugin(replication) + .plugin(mapreduce) + .plugin(SQLiteAdapter) diff --git a/src/pouchdb/shim.js b/src/pouchdb/shim.js new file mode 100644 index 000000000..bbd24a463 --- /dev/null +++ b/src/pouchdb/shim.js @@ -0,0 +1,6 @@ +import { shim } from 'react-native-quick-base64' + +shim() + +// Avoid using node dependent modules +process.browser = true From 6d95b9d4efad3739e57702e72dee9c970433abc7 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 28 May 2024 20:19:52 +0200 Subject: [PATCH 03/17] feat: Add cozy-pouch-link module --- __tests__/jestSetupFile.js | 10 ++++ package.json | 3 +- yarn.lock | 98 ++++++++++++++++++++++++++++++++++---- 3 files changed, 101 insertions(+), 10 deletions(-) diff --git a/__tests__/jestSetupFile.js b/__tests__/jestSetupFile.js index 1b7f0e0e9..026e3a601 100644 --- a/__tests__/jestSetupFile.js +++ b/__tests__/jestSetupFile.js @@ -130,3 +130,13 @@ jest.mock('../src/core/tools/env', () => ({ jest.mock('../src/pouchdb/pouchdb', () => ({})) jest.mock('react-native-quick-websql', () => ({})) + +class mockPouchLink { + constructor() {} +} + +jest.mock('cozy-pouch-link', () => { + return jest.fn().mockImplementation(() => { + return new mockPouchLink() + }) +}) diff --git a/package.json b/package.json index 479e29977..0208b2a38 100644 --- a/package.json +++ b/package.json @@ -55,13 +55,14 @@ "@sentry/integrations": "7.81.1", "@sentry/react-native": "5.16.0", "base-64": "^1.0.0", - "cozy-client": "^48.5.0", + "cozy-client": "^49.0.0", "cozy-clisk": "^0.36.1", "cozy-device-helper": "^2.7.0", "cozy-flags": "^3.2.0", "cozy-intent": "^2.22.0", "cozy-logger": "^1.10.0", "cozy-minilog": "3.3.1", + "cozy-pouch-link": "^49.0.0", "date-fns": "2.29.3", "events": "^3.3.0", "html-entities": "^2.3.3", diff --git a/yarn.lock b/yarn.lock index 544d8d0d9..814f63e9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8303,16 +8303,16 @@ cosmiconfig@^7.0.1: path-type "^4.0.0" yaml "^1.10.0" -cozy-client@^48.5.0: - version "48.5.0" - resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-48.5.0.tgz#c030ac3578466550cb30b545818aac9d5331eaa8" - integrity sha512-Bt+VH6mvif3qqOhAm5i9Ua7a5c7x6FSeLSWzrHm0fp8ALCsHw3LpKHVa+qGQNSNrkwG5ctBHO5wSR6ShmSxbZA== +cozy-client@^49.0.0: + version "49.0.0" + resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-49.0.0.tgz#c38f3bdefd58cbf827a368fe126cc9e27deb996d" + integrity sha512-AY22bxwQV+46+4rSVc+zYci8pPHspolBJ1IcqvxJ+DknZrehJ5AKJ55F9DzN3aPXVNCQzmw+wpNFgVP4gShFAw== dependencies: "@cozy/minilog" "1.0.0" "@types/jest" "^26.0.20" "@types/lodash" "^4.14.170" btoa "^1.2.1" - cozy-stack-client "^48.5.0" + cozy-stack-client "^49.0.0" date-fns "2.29.3" json-stable-stringify "^1.0.1" lodash "^4.17.13" @@ -8379,10 +8379,19 @@ cozy-minilog@3.3.1, cozy-minilog@^3.3.1: dependencies: microee "0.0.6" -cozy-stack-client@^48.5.0: - version "48.5.0" - resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-48.5.0.tgz#017f4c1ebcf7fdf9261aaa40ce4ea263421806d1" - integrity sha512-McwK/thwpbQTH2R+fOZzwVLnaScFzo0E91fbIcZOkFXRT6VM8WaUdQDeowlOaaw+w9R8167h0qwri+yeFbT/Ew== +cozy-pouch-link@^49.0.0: + version "49.0.0" + resolved "https://registry.yarnpkg.com/cozy-pouch-link/-/cozy-pouch-link-49.0.0.tgz#05644fbf7bbb7bf1af0869bca2b959e0ef2bd284" + integrity sha512-objXCSNvyGGNhzqb4PXwKNSqv54+E6p1eNhkEBlzrO6miXAeIYX5T0db3OQUuhiQdB69aYiExAVj5sCfUst3kw== + dependencies: + cozy-client "^49.0.0" + pouchdb-browser "^7.2.2" + pouchdb-find "^7.2.2" + +cozy-stack-client@^49.0.0: + version "49.0.0" + resolved "https://registry.yarnpkg.com/cozy-stack-client/-/cozy-stack-client-49.0.0.tgz#1bda328d0d62b00bb8895be5b991d59ad6b41cfc" + integrity sha512-mlh/hR9KsIve+et17P6WXlO33FjXftzXK8ovWAKr8zk+5FcD/wy/yxV/9Mr3Q+SSabdUbFbBIqu8kZncafUzdg== dependencies: detect-node "^2.0.4" mime "^2.4.0" @@ -16401,6 +16410,20 @@ postinstall-postinstall@^2.1.0: resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== +pouchdb-abstract-mapreduce@7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-7.3.1.tgz#96ff4a0f41cbe273f3f52fde003b719005a2093c" + integrity sha512-0zKXVFBvrfc1KnN0ggrB762JDmZnUpePHywo9Bq3Jy+L1FnoG7fXM5luFfvv5/T0gEw+ZTIwoocZECMnESBI9w== + dependencies: + pouchdb-binary-utils "7.3.1" + pouchdb-collate "7.3.1" + pouchdb-collections "7.3.1" + pouchdb-errors "7.3.1" + pouchdb-fetch "7.3.1" + pouchdb-mapreduce-utils "7.3.1" + pouchdb-md5 "7.3.1" + pouchdb-utils "7.3.1" + pouchdb-abstract-mapreduce@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-abstract-mapreduce/-/pouchdb-abstract-mapreduce-8.0.1.tgz#f45aa1424fdd272a76ceb5722a53b38c10a0ca81" @@ -16458,6 +16481,18 @@ pouchdb-binary-utils@8.0.1: dependencies: buffer-from "1.1.2" +pouchdb-browser@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-browser/-/pouchdb-browser-7.3.1.tgz#6b2f9f35f42d2c83fc205de5e0403c0aae7046aa" + integrity sha512-qZ8awkXl/woBHvEVqNHjDtwPDA7A9v4ItHtX1y1eVpKel4mlYqnIJ8K6pRcFUZmVaHinJW8K3uS32eHC1q0yOA== + dependencies: + argsarray "0.0.1" + immediate "3.3.0" + inherits "2.0.4" + spark-md5 "3.0.2" + uuid "8.3.2" + vuvuzela "1.0.3" + pouchdb-changes-filter@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-changes-filter/-/pouchdb-changes-filter-8.0.1.tgz#691b71b209dda12e950672ce44de2680606a98e4" @@ -16475,6 +16510,11 @@ pouchdb-checkpointer@8.0.1: pouchdb-collate "8.0.1" pouchdb-utils "8.0.1" +pouchdb-collate@7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-7.3.1.tgz#19d7b87dd173d1c765da8cc9987c5aa9eb24f11f" + integrity sha512-o4gyGqDMLMSNzf6EDTr3eHaH/JRMoqRhdc+eV+oA8u00nTBtr9wD+jypVe2LbgKLJ4NWqx2qVkXiTiQdUFtsLQ== + pouchdb-collate@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-collate/-/pouchdb-collate-8.0.1.tgz#14b6ad9330d2831fd8ef135de680060366502a1b" @@ -16515,6 +16555,15 @@ pouchdb-errors@8.0.1: resolved "https://registry.yarnpkg.com/pouchdb-errors/-/pouchdb-errors-8.0.1.tgz#d57afd57e07490d8d0b4ef19c10bfc85dbf27ae5" integrity sha512-H+ZsQxcG/JV3Tn29gnM6c9+lRPCN91ZYOkoIICsLjVRYgOTzN1AvNUD/G5JCB+81aI/u3fxZec0LEaZh6g6NHA== +pouchdb-fetch@7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-fetch/-/pouchdb-fetch-7.3.1.tgz#d54b1807be0f0a5d4b6d06e416c7d54952bbc348" + integrity sha512-205xAtvdHRPQ4fp1h9+RmT9oQabo9gafuPmWsS9aEl3ER54WbY8Vaj1JHZGbU4KtMTYvW7H5088zLS7Nrusuag== + dependencies: + abort-controller "3.0.0" + fetch-cookie "0.11.0" + node-fetch "2.6.7" + pouchdb-fetch@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-fetch/-/pouchdb-fetch-8.0.1.tgz#30a27a45eb24c20f346a04d906ba82bca5a3a525" @@ -16524,6 +16573,19 @@ pouchdb-fetch@8.0.1: fetch-cookie "0.11.0" node-fetch "2.6.7" +pouchdb-find@^7.2.2: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-find/-/pouchdb-find-7.3.1.tgz#07a633d5ee2bd731dae9f991281cd25212088d29" + integrity sha512-AeqUfAVY1c7IFaY36BRT0vIz9r4VTKq/YOWTmiqndOZUQ/pDGxyO2fNFal6NN3PyYww0JijlD377cPvhnrhJVA== + dependencies: + pouchdb-abstract-mapreduce "7.3.1" + pouchdb-collate "7.3.1" + pouchdb-errors "7.3.1" + pouchdb-fetch "7.3.1" + pouchdb-md5 "7.3.1" + pouchdb-selector-core "7.3.1" + pouchdb-utils "7.3.1" + pouchdb-generate-replication-id@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-generate-replication-id/-/pouchdb-generate-replication-id-8.0.1.tgz#2c473bdb7f5e5bc08337b3042841f186bf3d0b2b" @@ -16539,6 +16601,16 @@ pouchdb-json@^7.2.2: dependencies: vuvuzela "1.0.3" +pouchdb-mapreduce-utils@7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-7.3.1.tgz#f0ac2c8400fbedb705e9226082453ac7d3f2a066" + integrity sha512-oUMcq82+4pTGQ6dtrhgORHOVHZSr6w/5tFIUGlv7RABIDvJarL4snMawADjlpiEwPdiQ/ESG8Fqt8cxqvqsIgg== + dependencies: + argsarray "0.0.1" + inherits "2.0.4" + pouchdb-collections "7.3.1" + pouchdb-utils "7.3.1" + pouchdb-mapreduce-utils@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-mapreduce-utils/-/pouchdb-mapreduce-utils-8.0.1.tgz#a8acb1542aaf63a007b60f7a281dbbb94b49fcab" @@ -16594,6 +16666,14 @@ pouchdb-replication@^8.0.1: pouchdb-generate-replication-id "8.0.1" pouchdb-utils "8.0.1" +pouchdb-selector-core@7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-7.3.1.tgz#08245662de3d61f16ab8dae2b56ef622935b3fb3" + integrity sha512-HBX+nNGXcaL9z0uNpwSMRq2GNZd3EZXW+fe9rJHS0hvJohjZL7aRJLoaXfEdHPRTNW+CpjM3Rny60eGekQdI/w== + dependencies: + pouchdb-collate "7.3.1" + pouchdb-utils "7.3.1" + pouchdb-selector-core@8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/pouchdb-selector-core/-/pouchdb-selector-core-8.0.1.tgz#d52119b79bd34b69c27f4596dbb9e16373bbd92e" From 9876b0294339b50ac98eb51150475d64e0a333d8 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 31 May 2024 16:44:49 +0200 Subject: [PATCH 04/17] feat: Configure CozyClient to use CozyPouchLink We want the Flagship app to work when offline To make this possible we configure cozy-client with CozyPouchLink which role will be to synchronize necessary doctypes into a local PouchDB and serve them from it instead of from the cozy-stack when the device is offline For now the list of synchronized doctypes is hardcoded but in the future we expect to implement a dynamic list based on cozy-apps' manifests Related PR: cozy/cozy-client#1507 --- src/libs/client.js | 5 ++- src/libs/client.spec.js | 3 +- src/libs/clientHelpers/createClient.ts | 6 +++- src/pouchdb/getLinks.ts | 39 +++++++++++++++++++++ src/pouchdb/platformReactNative.appState.ts | 34 ++++++++++++++++++ src/pouchdb/platformReactNative.events.ts | 28 +++++++++++++++ src/pouchdb/platformReactNative.isOnline.ts | 5 +++ src/pouchdb/platformReactNative.netInfo.ts | 24 +++++++++++++ src/pouchdb/platformReactNative.storage.ts | 14 ++++++++ src/pouchdb/platformReactNative.ts | 12 +++++++ 10 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 src/pouchdb/getLinks.ts create mode 100644 src/pouchdb/platformReactNative.appState.ts create mode 100644 src/pouchdb/platformReactNative.events.ts create mode 100644 src/pouchdb/platformReactNative.isOnline.ts create mode 100644 src/pouchdb/platformReactNative.netInfo.ts create mode 100644 src/pouchdb/platformReactNative.storage.ts create mode 100644 src/pouchdb/platformReactNative.ts diff --git a/src/libs/client.js b/src/libs/client.js index 49206c162..f304bba49 100644 --- a/src/libs/client.js +++ b/src/libs/client.js @@ -30,6 +30,7 @@ export { } from '/libs/clientHelpers/initClient' export { call2FAInitClient } from '/libs/clientHelpers/twoFactorAuthentication' import { CozyPersistedStorageKeys, getData } from '/libs/localStore/storage' +import { getLinks } from '/pouchdb/getLinks' const log = Minilog('LoginScreen') @@ -44,6 +45,7 @@ export const getClient = async () => { return false } const { uri, oauthOptions, token } = oauthData + const links = getLinks() const client = new CozyClient({ uri, oauth: { token }, @@ -51,7 +53,8 @@ export const getClient = async () => { appMetadata: { slug: 'flagship', version: packageJSON.version - } + }, + links }) listenTokenRefresh(client) client.getStackClient().setOAuthOptions(oauthOptions) diff --git a/src/libs/client.spec.js b/src/libs/client.spec.js index 9de17df7a..6de3a03f8 100644 --- a/src/libs/client.spec.js +++ b/src/libs/client.spec.js @@ -62,7 +62,8 @@ describe('client', () => { appMetadata: { slug: 'flagship', version: packageJSON.version - } + }, + links: expect.anything() }) }) diff --git a/src/libs/clientHelpers/createClient.ts b/src/libs/clientHelpers/createClient.ts index 0a3a30bb6..8e16bc5bd 100644 --- a/src/libs/clientHelpers/createClient.ts +++ b/src/libs/clientHelpers/createClient.ts @@ -13,6 +13,7 @@ import googleServicesJson from '/../android/app/src/prod/google-services.json' import packageJSON from '../../../package.json' import { startListening } from '/app/domain/authentication/services/AuthService' +import { getLinks } from '/pouchdb/getLinks' /** * Create a CozyClient for the given Cozy instance and register it @@ -21,6 +22,8 @@ import { startListening } from '/app/domain/authentication/services/AuthService' * @returns {CozyClient} - The created and registered CozyClient */ export const createClient = async (instance: string): Promise => { + const links = getLinks() + const options = { scope: ['*'], oauth: { @@ -37,7 +40,8 @@ export const createClient = async (instance: string): Promise => { appMetadata: { slug: 'flagship', version: packageJSON.version - } + }, + links } const client = new CozyClient(options) diff --git a/src/pouchdb/getLinks.ts b/src/pouchdb/getLinks.ts new file mode 100644 index 000000000..5d3a91190 --- /dev/null +++ b/src/pouchdb/getLinks.ts @@ -0,0 +1,39 @@ +import { platformReactNative } from '/pouchdb/platformReactNative' + +import { default as PouchLink } from 'cozy-pouch-link' + +export const offlineDoctypes = [ + // cozy-home + 'io.cozy.accounts', + 'io.cozy.apps', + 'io.cozy.contacts', + 'io.cozy.files', + 'io.cozy.files.shortcuts', + 'io.cozy.home.settings', + 'io.cozy.jobs', + 'io.cozy.konnectors', + 'io.cozy.settings', + 'io.cozy.apps.suggestions', + 'io.cozy.triggers', + 'io.cozy.apps_registry', + + // mespapiers + 'io.cozy.bills', + 'io.cozy.sharings', + 'io.cozy.mespapiers.settings', + 'io.cozy.permissions' +] + +export const getLinks = () => { + const pouchLinkOptions = { + doctypes: offlineDoctypes, + initialSync: true, + platform: platformReactNative + } + + const pouchLink = new PouchLink({ + ...pouchLinkOptions + }) + + return [pouchLink] +} diff --git a/src/pouchdb/platformReactNative.appState.ts b/src/pouchdb/platformReactNative.appState.ts new file mode 100644 index 000000000..41d93b11c --- /dev/null +++ b/src/pouchdb/platformReactNative.appState.ts @@ -0,0 +1,34 @@ +import EventEmitter from 'events' + +import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native' + +import Minilog from 'cozy-minilog' + +const log = Minilog('🛋️ PlatormReactNative.appState') + +let appState = AppState.currentState +let appStateHandler: NativeEventSubscription | undefined = undefined + +export const listenAppState = (eventEmitter: EventEmitter): void => { + appStateHandler = AppState.addEventListener('change', nextAppState => { + log.debug('🛋️ AppState event', nextAppState) + if (isGoingToSleep(nextAppState)) { + eventEmitter.emit('resume') + } + if (isGoingToWakeUp(nextAppState)) { + eventEmitter.emit('pause') + } + + appState = nextAppState + }) +} + +export const stopListeningAppState = (): void => { + appStateHandler?.remove() +} + +const isGoingToSleep = (nextAppState: AppStateStatus): boolean => + Boolean(appState.match(/active/) && nextAppState === 'background') + +const isGoingToWakeUp = (nextAppState: AppStateStatus): boolean => + Boolean(appState.match(/background/) && nextAppState === 'active') diff --git a/src/pouchdb/platformReactNative.events.ts b/src/pouchdb/platformReactNative.events.ts new file mode 100644 index 000000000..8382f7853 --- /dev/null +++ b/src/pouchdb/platformReactNative.events.ts @@ -0,0 +1,28 @@ +import { EventEmitter } from 'events' + +import { listenAppState } from '/pouchdb/platformReactNative.appState' +import { listenNetInfo } from '/pouchdb/platformReactNative.netInfo' + +export const pouchDbEmitter = new EventEmitter() + +const listenPouchEvents = (): void => { + listenAppState(pouchDbEmitter) + listenNetInfo(pouchDbEmitter) +} + +listenPouchEvents() + +export const events = { + addEventListener: ( + eventName: string, + handler: (...args: unknown[]) => void + ): void => { + pouchDbEmitter.addListener(eventName, handler) + }, + removeEventListener: ( + eventName: string, + handler: (...args: unknown[]) => void + ): void => { + pouchDbEmitter.removeListener(eventName, handler) + } +} diff --git a/src/pouchdb/platformReactNative.isOnline.ts b/src/pouchdb/platformReactNative.isOnline.ts new file mode 100644 index 000000000..8081dad3c --- /dev/null +++ b/src/pouchdb/platformReactNative.isOnline.ts @@ -0,0 +1,5 @@ +import { NetService } from '/libs/services/NetService' + +export const isOnline = async (): Promise => { + return (await NetService.isConnected()) ?? true +} diff --git a/src/pouchdb/platformReactNative.netInfo.ts b/src/pouchdb/platformReactNative.netInfo.ts new file mode 100644 index 000000000..2d52a3b8a --- /dev/null +++ b/src/pouchdb/platformReactNative.netInfo.ts @@ -0,0 +1,24 @@ +import EventEmitter from 'events' + +import NetInfo, { NetInfoSubscription } from '@react-native-community/netinfo' + +import Minilog from 'cozy-minilog' + +const log = Minilog('🛋️ PlatormReactNative.netInfo') + +let netInfoHandler: NetInfoSubscription | undefined = undefined + +export const listenNetInfo = (eventEmitter: EventEmitter): void => { + netInfoHandler = NetInfo.addEventListener(state => { + log.debug('🛋️ NetInfo event', state.isConnected) + if (state.isConnected) { + eventEmitter.emit('online') + } else { + eventEmitter.emit('offline') + } + }) +} + +export const stopListeningNetInfo = (): void => { + netInfoHandler?.() +} diff --git a/src/pouchdb/platformReactNative.storage.ts b/src/pouchdb/platformReactNative.storage.ts new file mode 100644 index 000000000..f294bc4ca --- /dev/null +++ b/src/pouchdb/platformReactNative.storage.ts @@ -0,0 +1,14 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' + +export const storage = { + getItem: async (key: string): Promise => { + return AsyncStorage.getItem(key) + }, + setItem: async (key: string, value: string | undefined): Promise => { + if (value === undefined) return + return AsyncStorage.setItem(key, value) + }, + removeItem: async (key: string): Promise => { + return AsyncStorage.removeItem(key) + } +} diff --git a/src/pouchdb/platformReactNative.ts b/src/pouchdb/platformReactNative.ts new file mode 100644 index 000000000..9241e70d8 --- /dev/null +++ b/src/pouchdb/platformReactNative.ts @@ -0,0 +1,12 @@ +import { events } from '/pouchdb/platformReactNative.events' +import { isOnline } from '/pouchdb/platformReactNative.isOnline' +import { storage } from '/pouchdb/platformReactNative.storage' +import PouchDB from '/pouchdb/pouchdb' + +export const platformReactNative = { + storage, + events, + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + pouchAdapter: PouchDB, + isOnline +} From 4f7614cde2b6b57ebdca5efcfbac3a9fc31288c9 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 31 May 2024 16:44:40 +0200 Subject: [PATCH 05/17] feat: Configure CozyClient to also use StackLink (when online) In previous commit we configured cozy-client to use CozyPouchLink for its queries This commit also adds StackLink as the first Link so by default it will do its queries through the remote cozy-stack CozyClient has been modified to handle offline mode and redirect to the next link when it is detected Related PR: cozy/cozy-client#1507 --- src/pouchdb/getLinks.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/pouchdb/getLinks.ts b/src/pouchdb/getLinks.ts index 5d3a91190..ac6e565f9 100644 --- a/src/pouchdb/getLinks.ts +++ b/src/pouchdb/getLinks.ts @@ -1,5 +1,6 @@ import { platformReactNative } from '/pouchdb/platformReactNative' +import { CozyLink, StackLink } from 'cozy-client' import { default as PouchLink } from 'cozy-pouch-link' export const offlineDoctypes = [ @@ -24,16 +25,20 @@ export const offlineDoctypes = [ 'io.cozy.permissions' ] -export const getLinks = () => { +export const getLinks = (): CozyLink[] => { const pouchLinkOptions = { doctypes: offlineDoctypes, initialSync: true, platform: platformReactNative } + const stackLink = new StackLink({ + platform: platformReactNative + }) + const pouchLink = new PouchLink({ ...pouchLinkOptions }) - return [pouchLink] + return [stackLink, pouchLink] } From 4badb35404e4bd4ae9d6c7d3e36820491572b0fb Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 31 May 2024 16:44:24 +0200 Subject: [PATCH 06/17] feat: Add PouchDBFind plugin to the PouchDB configuration This plugin is required by cozy-client to process `find` queries Related PR: cozy/cozy-client#1507 --- src/pouchdb/pouchdb.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pouchdb/pouchdb.js b/src/pouchdb/pouchdb.js index c7ae74dae..c14b272e2 100644 --- a/src/pouchdb/pouchdb.js +++ b/src/pouchdb/pouchdb.js @@ -4,6 +4,7 @@ import 'react-native-get-random-values' import HttpPouch from 'pouchdb-adapter-http' import SQLiteAdapterFactory from 'pouchdb-adapter-react-native-sqlite' import PouchDB from 'pouchdb-core' +import PouchDBFind from 'pouchdb-find' import mapreduce from 'pouchdb-mapreduce' import replication from 'pouchdb-replication' import WebSQLite from 'react-native-quick-websql' @@ -11,6 +12,7 @@ import WebSQLite from 'react-native-quick-websql' const SQLiteAdapter = SQLiteAdapterFactory(WebSQLite) export default PouchDB.plugin(HttpPouch) + .plugin(PouchDBFind) .plugin(replication) .plugin(mapreduce) .plugin(SQLiteAdapter) From 28c007f4c967a3a3a4b60289898df1519171b37f Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Thu, 11 Jul 2024 18:23:34 +0200 Subject: [PATCH 07/17] feat: Add clientCachedStorage to handle CozyClient's requests cache PouchDB can handle only `client.query()` requests For all other requests, like `client.fetchJSON()` we want to be able to store the request result in the device's AsyncStorage so we can re-use this result when the device is offline Data is stored using the client's url and the request content as key (it can be a string or a full request object) --- src/libs/intents/localMethods.ts | 2 + .../localStore/clientCachedStorage.spec.ts | 202 ++++++++++++++++++ src/libs/localStore/clientCachedStorage.ts | 95 ++++++++ 3 files changed, 299 insertions(+) create mode 100644 src/libs/localStore/clientCachedStorage.spec.ts create mode 100644 src/libs/localStore/clientCachedStorage.ts diff --git a/src/libs/intents/localMethods.ts b/src/libs/intents/localMethods.ts index 48df7e8e5..362d1366b 100644 --- a/src/libs/intents/localMethods.ts +++ b/src/libs/intents/localMethods.ts @@ -22,6 +22,7 @@ import { setHomeThemeIntent } from '/libs/intents/setHomeThemeIntent' import strings from '/constants/strings.json' import { EnvService } from '/core/tools/env' import { clearCookies } from '/libs/httpserver/httpCookieManager' +import { clearClientCachedData } from '/libs/localStore/clientCachedStorage' import { clearCozyData } from '/libs/localStore/storage' import { getSharedMemoryIntent, @@ -72,6 +73,7 @@ export const asyncLogout = async (client?: CozyClient): Promise => { } await sendKonnectorsLogs(client) + await clearClientCachedData(client) await client.logout() await stopTrackingAndClearData() await deleteKeychain() diff --git a/src/libs/localStore/clientCachedStorage.spec.ts b/src/libs/localStore/clientCachedStorage.spec.ts new file mode 100644 index 000000000..ab82d502e --- /dev/null +++ b/src/libs/localStore/clientCachedStorage.spec.ts @@ -0,0 +1,202 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' + +import CozyClient from 'cozy-client' + +import { + clearClientCachedData, + getClientCachedData, + storeClientCachedData +} from '/libs/localStore/clientCachedStorage' +import { AppData } from '/libs/httpserver/models' +import { + clearAllData, + CozyPersistedStorageKeys, + storeData +} from '/libs/localStore/storage' + +const { getAllKeys } = AsyncStorage + +describe('clientCachedStorage', () => { + beforeEach(async () => { + await clearAllData() + }) + + describe('key tests', () => { + it('should use raw request for key when string', async () => { + const request = 'SomeRequestName' + + await storeClientCachedData(aliceClient, request, getFakeAppData()) + const keys = await getAllKeys() + + expect(keys).toStrictEqual([ + '@ccCache_alice.mycozy.cloud_SomeRequestName' + ]) + }) + + it('should convert request to base64 for key when request CozyClientRequest object', async () => { + const request = { + method: 'GET', + path: '/some/path', + body: {}, + options: {} + } + + await storeClientCachedData(aliceClient, request, getFakeAppData()) + const keys = await getAllKeys() + + expect(keys).toStrictEqual([ + '@ccCache_alice.mycozy.cloud_eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiL3NvbWUvcGF0aCIsImJvZHkiOnt9LCJvcHRpb25zIjp7fX0=' + ]) + }) + }) + + describe('isolation tests', () => { + it('should store as alice and retrieve as alice', async () => { + const request = 'SomeRequestName' + + await storeClientCachedData(aliceClient, request, getFakeAppData()) + const result = await getClientCachedData(aliceClient, request) + expect(result).toStrictEqual(getFakeAppData()) + }) + + it('should store as alice and not retrieve as alice with port', async () => { + const request = 'SomeRequestName' + await storeClientCachedData(aliceClient, request, getFakeAppData()) + const result = await getClientCachedData(aliceClientWithPort, request) + expect(result).toStrictEqual(null) + }) + + it('should store as alice and bob and retrieve as alice and bob', async () => { + const aliceRequest = 'SomeRequestName' + const bobRequest = 'SomeRequestName' + await storeClientCachedData( + aliceClient, + aliceRequest, + getFakeAppData('TestAlice') + ) + await storeClientCachedData( + bobClient, + bobRequest, + getFakeAppData('TestBob') + ) + const aliceResult = await getClientCachedData(aliceClient, aliceRequest) + const bobResult = await getClientCachedData(bobClient, bobRequest) + expect(aliceResult).toStrictEqual(getFakeAppData('TestAlice')) + expect(bobResult).toStrictEqual(getFakeAppData('TestBob')) + }) + + it('should store as alice and not retrieve as bob', async () => { + const request = 'SomeRequestName' + await storeClientCachedData( + aliceClient, + request, + getFakeAppData('TestAlice') + ) + const result = await getClientCachedData(bobClient, request) + expect(result).toStrictEqual(null) + }) + }) + + describe('clearClientCachedData', () => { + it('should clear only data relative to clientCachedStorage', async () => { + await storeData( + // @ts-expect-error Type validation is handled on clientCachedStorage + '@ccCache_alice.mycozy.cloud_SomeRequestName', + 'SomeValue' + ) + await storeData( + // @ts-expect-error Type validation is handled on clientCachedStorage + '@ccCache_alice.mycozy.cloud_eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiL3NvbWUvcGF0aCIsImJvZHkiOnt9LCJvcHRpb25zIjp7fX0=', + 'SomeValue' + ) + await storeData(CozyPersistedStorageKeys.Activities, 'SomeValue') + await storeData(CozyPersistedStorageKeys.AutoLockEnabled, 'SomeValue') + + const keys = await getAllKeys() + expect(keys).toStrictEqual([ + '@ccCache_alice.mycozy.cloud_SomeRequestName', + '@ccCache_alice.mycozy.cloud_eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiL3NvbWUvcGF0aCIsImJvZHkiOnt9LCJvcHRpb25zIjp7fX0=', + CozyPersistedStorageKeys.Activities, + CozyPersistedStorageKeys.AutoLockEnabled + ]) + + await clearClientCachedData(aliceClient) + + const keys2 = await getAllKeys() + expect(keys2).toStrictEqual([ + CozyPersistedStorageKeys.Activities, + CozyPersistedStorageKeys.AutoLockEnabled + ]) + }) + + it('should clear only data relative to current client', async () => { + await storeData( + // @ts-expect-error Type validation is handled on clientCachedStorage + '@ccCache_alice.mycozy.cloud_SomeRequestName', + 'SomeValue' + ) + await storeData( + // @ts-expect-error Type validation is handled on clientCachedStorage + '@ccCache_alice.mycozy.cloud_eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiL3NvbWUvcGF0aCIsImJvZHkiOnt9LCJvcHRpb25zIjp7fX0=', + 'SomeValue' + ) + await storeData( + // @ts-expect-error Type validation is handled on clientCachedStorage + '@ccCache_bob.mycozy.cloud_SomeRequestName', + 'SomeValue' + ) + + const keys = await getAllKeys() + expect(keys).toStrictEqual([ + '@ccCache_alice.mycozy.cloud_SomeRequestName', + '@ccCache_alice.mycozy.cloud_eyJtZXRob2QiOiJHRVQiLCJwYXRoIjoiL3NvbWUvcGF0aCIsImJvZHkiOnt9LCJvcHRpb25zIjp7fX0=', + '@ccCache_bob.mycozy.cloud_SomeRequestName' + ]) + + await clearClientCachedData(aliceClient) + + const keys2 = await getAllKeys() + expect(keys2).toStrictEqual(['@ccCache_bob.mycozy.cloud_SomeRequestName']) + }) + }) +}) + +const aliceClient = { + getStackClient: () => ({ uri: 'https://alice.mycozy.cloud' }) +} as CozyClient + +const aliceClientWithPort = { + getStackClient: () => ({ uri: 'https://alice.mycozy.cloud:8080' }) +} as CozyClient + +const bobClient = { + getStackClient: () => ({ uri: 'https://bob.mycozy.cloud' }) +} as CozyClient + +const getFakeAppData = (id = 'SomeId'): AppData => ({ + attributes: { + AppEditor: 'SomeAppEditor', + AppName: 'SomeAppName', + AppNamePrefix: 'SomeAppNamePrefix', + AppSlug: 'SomeAppSlug', + Capabilities: 'SomeCapabilities', + Cookie: 'SomeCookie', + CozyBar: 'SomeCozyBar', + CozyClientJS: 'SomeCozyClientJS', + CozyFonts: 'SomeCozyFonts', + DefaultWallpaper: 'SomeDefaultWallpaper', + Domain: 'SomeDomain', + Favicon: 'SomeFavicon', + Flags: 'SomeFlags', + IconPath: 'SomeIconPath', + Locale: 'SomeLocale', + SubDomain: 'SomeSubDomain', + ThemeCSS: 'SomeThemeCSS', + Token: 'SomeToken', + Tracking: 'SomeTracking' + }, + id: id, + links: { self: 'SomeSelf' }, + meta: {}, + type: 'SomeType' +}) diff --git a/src/libs/localStore/clientCachedStorage.ts b/src/libs/localStore/clientCachedStorage.ts new file mode 100644 index 000000000..15dec9ab5 --- /dev/null +++ b/src/libs/localStore/clientCachedStorage.ts @@ -0,0 +1,95 @@ +import AsyncStorage from '@react-native-async-storage/async-storage' + +import CozyClient from 'cozy-client' +import Minilog from 'cozy-minilog' + +import { normalizeFqdn } from '/libs/functions/stringHelpers' +import { AppData } from '/libs/httpserver/models' +import { getData, storeData } from '/libs/localStore/storage' + +const log = Minilog('clientCachedStorage.ts') + +const clientCachePrefix = '@ccCache_' + +type CozyClientCacheKey = `@ccCache_${string}` + +type CacheableObject = AppData + +interface CozyClientRequest { + method: unknown + path: unknown + body: unknown + options: unknown +} + +const { getAllKeys, removeItem } = AsyncStorage + +export const storeClientCachedData = async ( + client: CozyClient | null, + request: string | CozyClientRequest, + result: CacheableObject +): Promise => { + if (!client) return + + const key = formatKey(client, request) + + // @ts-expect-error Keys and values are already checked here as an CozyClientCacheKey + await storeData(key, result) +} + +export const getClientCachedData = async ( + client: CozyClient | null, + request: string | CozyClientRequest +): Promise => { + if (!client) return null + + const key = formatKey(client, request) + + // @ts-expect-error Keys and values are already checked here as an CozyClientCacheKey + const result = await getData(key) + + return result +} + +export const clearClientCachedData = async ( + client: CozyClient | null +): Promise => { + try { + if (!client) return + + const normalizedFqdn = getNormalizedFqdn(client) + const keys = await getAllKeys() + + const clientCacheKeys = keys.filter(k => + k.startsWith(`${clientCachePrefix}${normalizedFqdn}`) + ) + + for (const key of clientCacheKeys) { + await removeItem(key) + } + } catch (error) { + log.error(`Failed to clear ClientCache data from persistent storage`, error) + } +} + +const formatKey = ( + client: CozyClient, + request: string | CozyClientRequest +): CozyClientCacheKey => { + const normalizedFqdn = getNormalizedFqdn(client) + + const key = + typeof request === 'string' ? request : btoa(JSON.stringify(request)) + + return `${clientCachePrefix}${normalizedFqdn}_${key}` +} + +const getNormalizedFqdn = (client: CozyClient): string => { + const rootURL = client.getStackClient().uri + + const { host: fqdn } = new URL(rootURL) + + const normalizedFqdn = normalizeFqdn(fqdn) + + return normalizedFqdn +} From 032029765dad35c610109bfff49313cb52aa6f84 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Thu, 11 Jul 2024 18:29:11 +0200 Subject: [PATCH 08/17] feat: Cache `/apps/:slug/open` request for offline support `/apps/:slug/open` request is based on `client.fetchJSON()` and is on the critical execution path for the application to boot So we want to use the new caching mechanism from previous commit in order to retrieve this request's cached result if the application is booted while the device is offline --- src/libs/client.js | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/src/libs/client.js b/src/libs/client.js index f304bba49..a5612c9c8 100644 --- a/src/libs/client.js +++ b/src/libs/client.js @@ -29,6 +29,10 @@ export { callOnboardingInitClient } from '/libs/clientHelpers/initClient' export { call2FAInitClient } from '/libs/clientHelpers/twoFactorAuthentication' +import { + getClientCachedData, + storeClientCachedData +} from '/libs/localStore/clientCachedStorage' import { CozyPersistedStorageKeys, getData } from '/libs/localStore/storage' import { getLinks } from '/pouchdb/getLinks' @@ -110,6 +114,7 @@ export const fetchPublicData = async client => { */ export const fetchCozyDataForSlug = async (slug, client, cookie) => { + const cacheKey = `CozyData_${slug}` const stackClient = client.getStackClient() const options = cookie @@ -123,14 +128,28 @@ export const fetchCozyDataForSlug = async (slug, client, cookie) => { } : undefined - const result = await stackClient.fetchJSON( - 'GET', - `/apps/${slug}/open`, - undefined, - options - ) + try { + const result = await stackClient.fetchJSON( + 'GET', + `/apps/${slug}/open`, + undefined, + options + ) + + storeClientCachedData(client, cacheKey, result) - return result + return result + } catch (err) { + if (err.message === 'Network request failed') { + const cachedResult = await getClientCachedData(client, cacheKey) + + if (cachedResult) { + return cachedResult + } + } + + throw err + } } /** From b5e9ba0bc24f7770f4d6b572d8525d7fbb6c7927 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 24 Sep 2024 12:52:48 +0200 Subject: [PATCH 09/17] feat: Upgrade cozy-intent to `2.23.0` `cozy-intent` has been upgraded to `2.23.0` to retrieve new interfaces for FlagshipLink and files downloading Related PR: cozy/cozy-libs#2562 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 0208b2a38..8b60fc3e6 100644 --- a/package.json +++ b/package.json @@ -59,7 +59,7 @@ "cozy-clisk": "^0.36.1", "cozy-device-helper": "^2.7.0", "cozy-flags": "^3.2.0", - "cozy-intent": "^2.22.0", + "cozy-intent": "^2.23.0", "cozy-logger": "^1.10.0", "cozy-minilog": "3.3.1", "cozy-pouch-link": "^49.0.0", diff --git a/yarn.lock b/yarn.lock index 814f63e9c..040dd2df6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8356,10 +8356,10 @@ cozy-flags@^3.2.0: dependencies: microee "^0.0.6" -cozy-intent@^2.22.0: - version "2.22.0" - resolved "https://registry.yarnpkg.com/cozy-intent/-/cozy-intent-2.22.0.tgz#a4333463ca934d2a5cfe34a23b0d6f0e50d27934" - integrity sha512-aCIlwLuia5llX36eubgbkah3vR3709V7VFDWl2hndvdmyjZBHh1siJUlJxpA5nYayqJkLy7aC4bdfGpTetgoCQ== +cozy-intent@^2.23.0: + version "2.23.0" + resolved "https://registry.yarnpkg.com/cozy-intent/-/cozy-intent-2.23.0.tgz#b6f3a407413df05c108e848b9dcb074b8780824b" + integrity sha512-DFn0ny4B4HpOE+3PYuZTTa074gRnFHqID+XaJ3gY2OrPL2xUQKEZmmFLp2bPVWThi5FvgvsU3EQeWPHZNQPbaQ== dependencies: cozy-minilog "^3.3.1" post-me "0.4.5" From 9f7493c3e4e39feb00de9dce32b256f738be4af8 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 30 Jul 2024 19:14:51 +0200 Subject: [PATCH 10/17] feat: Implement FlagshipLinkRequest interface through localMethods In previous commits we configured the application's cozy-client to use CozyPouchLink This link is configured for all react-native side queries, but not for cozy-app queries as they are served inside of WebViews and use a different cozy-client instance We want cozy-apps to benefits from the CozyPouchLink by redirecting their queries to the react-native side using the new FlagshipLink interface With this interface, all cozy-apps queries can be redirected to the react-native side using cozy-intent/post-me In order to intercept them, then we should declare `FlagshipLinkRequest()` method `localMethods` Related PR: cozy/cozy-client#1505 --- src/@types/cozy-client.d.ts | 12 +++++++++++- src/libs/intents/flagshipLink.ts | 33 ++++++++++++++++++++++++++++++++ src/libs/intents/localMethods.ts | 5 ++++- 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 src/libs/intents/flagshipLink.ts diff --git a/src/@types/cozy-client.d.ts b/src/@types/cozy-client.d.ts index 7bb4fc2af..0238cc1d1 100644 --- a/src/@types/cozy-client.d.ts +++ b/src/@types/cozy-client.d.ts @@ -1,7 +1,13 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import 'cozy-client' -import { FileDocument, CozyClientDocument } from 'cozy-client/types/types' +import { QueryDefinition } from 'cozy-client' +import { + FileDocument, + CozyClientDocument, + QueryOptions, + QueryResult +} from 'cozy-client/types/types' declare module 'cozy-client' { interface ClientOptions { @@ -157,6 +163,10 @@ declare module 'cozy-client' { on: (event: string, callback: () => void) => void removeListener: (event: string, callback: () => void) => void logout: () => Promise + query: ( + queryDefinition: QueryDefinition, + options?: QueryOptions + ) => Promise } export const createMockClient = (options?: ClientOptions): CozyClient => diff --git a/src/libs/intents/flagshipLink.ts b/src/libs/intents/flagshipLink.ts new file mode 100644 index 000000000..1248cd2a3 --- /dev/null +++ b/src/libs/intents/flagshipLink.ts @@ -0,0 +1,33 @@ +import CozyClient, { QueryDefinition } from 'cozy-client' +import type { QueryResult } from 'cozy-client/types/types' +import Minilog from 'cozy-minilog' + +import { getErrorMessage } from '/libs/functions/getErrorMessage' + +const log = Minilog('⛳🔗 flagshipLink') + +export const flagshipLinkRequest = async ( + operation: QueryDefinition, + client: CozyClient | undefined +): Promise => { + try { + if (!client) { + throw new Error( + 'FlagshipLinkRequest should not be called with undefined client' + ) + } + + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const result = await client.query(operation) + + // eslint-disable-next-line @typescript-eslint/no-unsafe-return + return result + } catch (error) { + const errorMessage = getErrorMessage(error) + log.error( + `Something when wrong while processing FlagshipLinkRequest: ${errorMessage}`, + operation + ) + throw error + } +} diff --git a/src/libs/intents/localMethods.ts b/src/libs/intents/localMethods.ts index 362d1366b..0c68a441b 100644 --- a/src/libs/intents/localMethods.ts +++ b/src/libs/intents/localMethods.ts @@ -1,7 +1,7 @@ import { Linking } from 'react-native' import { getDeviceName } from 'react-native-device-info' -import CozyClient from 'cozy-client' +import CozyClient, { QueryDefinition } from 'cozy-client' import { FlagshipUI, NativeMethodsRegisterWithOptions, @@ -36,6 +36,7 @@ import { openApp } from '/libs/functions/openApp' import { routes } from '/constants/routes' import { sendKonnectorsLogs } from '/libs/konnectors/sendKonnectorsLogs' import { setDefaultRedirection } from '/libs/defaultRedirection/defaultRedirection' +import { flagshipLinkRequest } from '/libs/intents/flagshipLink' import { setFlagshipUI } from '/libs/intents/setFlagshipUI' import { showInAppBrowser, closeInAppBrowser } from '/libs/intents/InAppBrowser' import { isBiometryDenied } from '/app/domain/authentication/services/BiometryService' @@ -398,6 +399,8 @@ export const localMethods = ( _options: PostMeMessageOptions, colorScheme: string | undefined ) => Promise.resolve(setColorScheme(colorScheme)), + flagshipLinkRequest: (_options, operation) => + flagshipLinkRequest(operation as QueryDefinition, client), ...mergedMethods } } From d0ee38053d8cb876b5ae28a938b61e57a104729a Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Thu, 11 Jul 2024 18:50:31 +0200 Subject: [PATCH 11/17] feat: Enable CacheMode for CozyProxyWebView on android when offline When a cozy-app's WebView is served offline, then the cozy-app bundle is served from local folder using the CozyProxyWebview, and since previous commits, the cozy-client's queries are served through `FlagshipLink` With those mechanisms, nearly all data are available offline except two things: - cozy-stack static assets (i.e. some css files, avatar, partners logos etc) - `fetchJSON()` requests This commit tries to handle the static assets part Those assets are often served with HTTP cache activated, and so the WebView should be able to load them correctly when the device is offline. However on Android, the WebView's cache seems not to persist after the application is closed Activating the `cacheMode=LOAD_CACHE_ELSE_NETWORK` seems to fix this behavior. But it prioritizes too much the cache over fresh data, so we want to activate it only when strictly necessary, which is when the application is offline This also allows to load partners logos that are not cached by the cozy-stack (as of today). But we expect to modify the cozy-stack to enable cache on them --- .../webviews/CozyProxyWebView.functions.js | 4 ++- src/components/webviews/CozyProxyWebView.js | 3 ++ .../webviews/CozyProxyWebView.spec.js | 5 +++- src/libs/client.js | 19 +++++++++++-- src/libs/httpserver/httpServerProvider.tsx | 28 +++++++++++++++---- src/libs/httpserver/indexDataFetcher.spec.ts | 21 ++++++++++++-- src/libs/httpserver/indexDataFetcher.ts | 4 ++- 7 files changed, 71 insertions(+), 13 deletions(-) diff --git a/src/components/webviews/CozyProxyWebView.functions.js b/src/components/webviews/CozyProxyWebView.functions.js index eb6f6c84f..adece7ad4 100644 --- a/src/components/webviews/CozyProxyWebView.functions.js +++ b/src/components/webviews/CozyProxyWebView.functions.js @@ -31,7 +31,8 @@ export const initHtmlContent = async ({ return } - const htmlContent = await httpServerContext.getIndexHtmlForSlug(slug, client) + const { html: htmlContent, source: htmlSource } = + await httpServerContext.getIndexHtmlForSlug(slug, client) if ( !cookieAlreadyExists && @@ -47,6 +48,7 @@ export const initHtmlContent = async ({ setHtmlContentCreationDate(Date.now()) dispatch(oldState => ({ ...oldState, + activateCache: htmlSource === 'cache' && Platform.OS === 'android', html: htmlContent, nativeConfig: nativeConfigActual, source: sourceActual diff --git a/src/components/webviews/CozyProxyWebView.js b/src/components/webviews/CozyProxyWebView.js index 10cb03c42..93b977c86 100644 --- a/src/components/webviews/CozyProxyWebView.js +++ b/src/components/webviews/CozyProxyWebView.js @@ -124,6 +124,9 @@ export const CozyProxyWebView = ({ dispatch(oldState => ({ ...oldState, isLoading: false })) onLoad?.(syntheticEvent) }} + cacheMode={ + state.activateCache ? 'LOAD_CACHE_ELSE_NETWORK' : 'LOAD_DEFAULT' + } {...props} /> ) : null} diff --git a/src/components/webviews/CozyProxyWebView.spec.js b/src/components/webviews/CozyProxyWebView.spec.js index 9a4808230..c2fdea139 100644 --- a/src/components/webviews/CozyProxyWebView.spec.js +++ b/src/components/webviews/CozyProxyWebView.spec.js @@ -24,7 +24,10 @@ describe('CozyWebview', () => { describe('OAuth Client Limit', () => { const httpServerContext = { - getIndexHtmlForSlug: jest.fn() + getIndexHtmlForSlug: jest.fn().mockResolvedValue({ + source: 'stack', + html: 'SOME_HTML' + }) } const href = 'https://claude-home.mycozy.cloud' const client = {} diff --git a/src/libs/client.js b/src/libs/client.js index a5612c9c8..d0efd3c35 100644 --- a/src/libs/client.js +++ b/src/libs/client.js @@ -103,6 +103,13 @@ export const fetchPublicData = async client => { } } +/** + * @template T + * @typedef {object} CozyDataStackOrCache + * @property {'stack'|'cache'} source - Source of the retrieved data + * @property {T} data - The appliation data + */ + /** * Fetches the data that is used to display a cozy application. * @@ -110,7 +117,7 @@ export const fetchPublicData = async client => { * @param {string} slug - The application slug * @param {object} client - A CozyClient instance * @param {object} [cookie] - An object containing a name and value property - * @returns {Promise} - The application data + * @returns {Promise>} - The application data */ export const fetchCozyDataForSlug = async (slug, client, cookie) => { @@ -138,13 +145,19 @@ export const fetchCozyDataForSlug = async (slug, client, cookie) => { storeClientCachedData(client, cacheKey, result) - return result + return { + source: 'stack', + data: result.data + } } catch (err) { if (err.message === 'Network request failed') { const cachedResult = await getClientCachedData(client, cacheKey) if (cachedResult) { - return cachedResult + return { + source: 'cache', + data: cachedResult.data + } } } diff --git a/src/libs/httpserver/httpServerProvider.tsx b/src/libs/httpserver/httpServerProvider.tsx index 3cf204e17..ac72d316a 100644 --- a/src/libs/httpserver/httpServerProvider.tsx +++ b/src/libs/httpserver/httpServerProvider.tsx @@ -35,6 +35,11 @@ const DEFAULT_PORT = Config.HTTP_SERVER_DEFAULT_PORT ? Number(Config.HTTP_SERVER_DEFAULT_PORT) : 5759 +interface IndexHtmlForSlug { + source: 'stack' | 'cache' + html: string +} + interface HttpServerState { server: HttpServer | undefined securityKey: string @@ -43,7 +48,7 @@ interface HttpServerState { getIndexHtmlForSlug: ( slug: string, client: CozyClient - ) => Promise + ) => Promise } interface SecurityKeyResult { @@ -118,7 +123,7 @@ export const HttpServerProvider = ( const getIndexHtmlForSlug = async ( slug: string, client: CozyClient - ): Promise => { + ): Promise => { try { if (!serverInstance) { throw new Error('ServerInstance is null, should not happen') @@ -128,7 +133,10 @@ export const HttpServerProvider = ( const { host: fqdn } = new URL(rootURL) - const { cookie, templateValues } = await fetchAppDataForSlug(slug, client) + const { cookie, source, templateValues } = await fetchAppDataForSlug( + slug, + client + ) await setCookie(cookie, client) const rawHtml = await getIndexForFqdnAndSlug(fqdn, slug) @@ -146,20 +154,30 @@ export const HttpServerProvider = ( indexData: templateValues }) if (slug === 'home') { - return flow( + const html = flow( addColorSchemeMetaIfNecessary, addBarStyles, addBodyClasses, addMetaAttributes )(computedHtml) + + return { + source, + html + } } else { // We do not need the bar styles for other app. We only need it for // the Home application since this is the only "immersive app" - return flow( + const html = flow( addColorSchemeMetaIfNecessary, addBodyClasses, addMetaAttributes )(computedHtml) + + return { + source, + html + } } } catch (err) { const errorMessage = getErrorMessage(err) diff --git a/src/libs/httpserver/indexDataFetcher.spec.ts b/src/libs/httpserver/indexDataFetcher.spec.ts index 138642aef..9e9737b72 100644 --- a/src/libs/httpserver/indexDataFetcher.spec.ts +++ b/src/libs/httpserver/indexDataFetcher.spec.ts @@ -12,7 +12,7 @@ jest.mock('@react-native-cookies/cookies', () => ({ })) const mockedFetchCozyDataForSlug = fetchCozyDataForSlug as jest.MockedFunction< - typeof fetchCozyDataForSlug + typeof fetchCozyDataForSlug > describe('indexDataFetcher', () => { @@ -37,7 +37,23 @@ describe('indexDataFetcher', () => { }) }) -const mockStackResult = { +interface StackResultData { + type: string + id: string + attributes: Record + meta: unknown + links: { + self: string + } +} + +interface StackResult { + source: 'stack' + data: StackResultData +} + +const mockStackResult: StackResult = { + source: 'stack', data: { type: 'io.cozy.apps.open', id: 'home', @@ -72,6 +88,7 @@ const mockStackResult = { const expectedResult = { cookie: 'SOME_COOKIE', + source: 'stack', templateValues: { AppEditor: 'Cozy', AppName: 'Home', diff --git a/src/libs/httpserver/indexDataFetcher.ts b/src/libs/httpserver/indexDataFetcher.ts index 25161ca0c..b42f037b4 100644 --- a/src/libs/httpserver/indexDataFetcher.ts +++ b/src/libs/httpserver/indexDataFetcher.ts @@ -11,6 +11,7 @@ export type TemplateValues = Omit & { } interface FetchAppDataForSlugResult { + source: 'stack' | 'cache' cookie: AppAttributes['Cookie'] templateValues: TemplateValues } @@ -23,7 +24,7 @@ export const fetchAppDataForSlug = async ( ): Promise => { try { const storedCookie = await getCookie(client) - const cozyDataResult = await fetchCozyDataForSlug<{ data: AppData }>( + const cozyDataResult = await fetchCozyDataForSlug( slug, client, storedCookie @@ -57,6 +58,7 @@ export const fetchAppDataForSlug = async ( return { cookie, + source: cozyDataResult.source, templateValues: { ...cozyDataAttributes, // The following attributes have to be sanitized to avoid semantic quotes. From 6f784de8632e2e448ca3a9ca8b4efff9f591f19f Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 30 Jul 2024 19:19:22 +0200 Subject: [PATCH 12/17] feat: Ignore queries warmup on PouchLink With previous changes, we now expect the CozyPouchLink to be the last link of the chain, so forwarding the query would result to an exception thrown This mean we cannot forward the query when warmup queries are not finished yet So we want to allow CozyPouchLink to ignore the verification step and process the query independently of the warmup queries status To allow this we introduce the `ignoreWarmup` parameter. When set to `true` the CozyPouchLink will process the query even if warmup is not finished yet Related PR: cozy/cozy-client#1506 --- src/pouchdb/getLinks.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/pouchdb/getLinks.ts b/src/pouchdb/getLinks.ts index ac6e565f9..5ad1d6abe 100644 --- a/src/pouchdb/getLinks.ts +++ b/src/pouchdb/getLinks.ts @@ -29,7 +29,8 @@ export const getLinks = (): CozyLink[] => { const pouchLinkOptions = { doctypes: offlineDoctypes, initialSync: true, - platform: platformReactNative + platform: platformReactNative, + ignoreWarmup: true } const stackLink = new StackLink({ From dd1b07a033811fd674e530ee7aa72d0078a50431 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 26 Jul 2024 17:34:58 +0200 Subject: [PATCH 13/17] feat: Declare schemas into cozy-client instance Some cozy-apps declare a data `schema` into cozy-client instance This schema is then used for processing queries As we now process cozy-app queries on the react-native side through FlagshipLinkRequest, we want to declared this schema in the Flagship app's cozy-client For now we only need to implement the one from cozy-home The ideal implementation would be to extract it from the cozy-app's bundle, but we did not implement anything to support this (we should first investigate how to do this). So for now it is hardcoded --- src/components/webviews/CozyWebview.spec.js | 1 + src/libs/client.js | 4 +- src/libs/client.spec.js | 3 +- src/libs/clientHelpers/createClient.ts | 4 +- src/pouchdb/schema.js | 56 ++++++++++++++++++++ src/screens/konnectors/LauncherView.spec.jsx | 1 + 6 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 src/pouchdb/schema.js diff --git a/src/components/webviews/CozyWebview.spec.js b/src/components/webviews/CozyWebview.spec.js index fa1b6e786..8efaf03b1 100644 --- a/src/components/webviews/CozyWebview.spec.js +++ b/src/components/webviews/CozyWebview.spec.js @@ -63,6 +63,7 @@ jest.mock('cozy-intent', () => ({ })) jest.mock('cozy-client', () => ({ + ...jest.requireActual('cozy-client'), useClient: jest.fn().mockReturnValue({}), useInstanceInfo: jest.fn().mockReturnValue({}) })) diff --git a/src/libs/client.js b/src/libs/client.js index d0efd3c35..76a32e393 100644 --- a/src/libs/client.js +++ b/src/libs/client.js @@ -35,6 +35,7 @@ import { } from '/libs/localStore/clientCachedStorage' import { CozyPersistedStorageKeys, getData } from '/libs/localStore/storage' import { getLinks } from '/pouchdb/getLinks' +import schema from '/pouchdb/schema' const log = Minilog('LoginScreen') @@ -58,7 +59,8 @@ export const getClient = async () => { slug: 'flagship', version: packageJSON.version }, - links + links, + schema }) listenTokenRefresh(client) client.getStackClient().setOAuthOptions(oauthOptions) diff --git a/src/libs/client.spec.js b/src/libs/client.spec.js index 6de3a03f8..0dc42695b 100644 --- a/src/libs/client.spec.js +++ b/src/libs/client.spec.js @@ -63,7 +63,8 @@ describe('client', () => { slug: 'flagship', version: packageJSON.version }, - links: expect.anything() + links: expect.anything(), + schema: expect.anything() }) }) diff --git a/src/libs/clientHelpers/createClient.ts b/src/libs/clientHelpers/createClient.ts index 8e16bc5bd..e53bdb70b 100644 --- a/src/libs/clientHelpers/createClient.ts +++ b/src/libs/clientHelpers/createClient.ts @@ -14,6 +14,7 @@ import packageJSON from '../../../package.json' import { startListening } from '/app/domain/authentication/services/AuthService' import { getLinks } from '/pouchdb/getLinks' +import schema from '/pouchdb/schema' /** * Create a CozyClient for the given Cozy instance and register it @@ -41,7 +42,8 @@ export const createClient = async (instance: string): Promise => { slug: 'flagship', version: packageJSON.version }, - links + links, + schema } const client = new CozyClient(options) diff --git a/src/pouchdb/schema.js b/src/pouchdb/schema.js new file mode 100644 index 000000000..b382eb36e --- /dev/null +++ b/src/pouchdb/schema.js @@ -0,0 +1,56 @@ +import { QueryDefinition, HasMany } from 'cozy-client' + +const CONTACTS_DOCTYPE = 'io.cozy.contacts' +const FILES_DOCTYPE = 'io.cozy.files' +const BILLS_DOCTYPE = 'io.cozy.bills' + +class HasManyBills extends HasMany { + get data() { + const refs = this.target.relationships.referenced_by.data + return refs + ? refs + .map(ref => { + if (ref.type === BILLS_DOCTYPE) { + return this.get(ref.type, ref.id) + } + }) + .filter(Boolean) + : [] + } + + static query(doc, client, assoc) { + if ( + !doc.relationships || + !doc.relationships.referenced_by || + !doc.relationships.referenced_by.data + ) { + return null + } + + const included = doc.relationships.referenced_by.data + const ids = included + .filter(inc => inc.type === assoc.doctype) + .map(inc => inc.id) + + return new QueryDefinition({ doctype: assoc.doctype, ids }) + } +} + +// the documents schema, necessary for CozyClient +export default { + contacts: { + doctype: CONTACTS_DOCTYPE, + attributes: {}, + relationships: {} + }, + files: { + doctype: FILES_DOCTYPE, + attributes: {}, + relationships: { + bills: { + type: HasManyBills, + doctype: BILLS_DOCTYPE + } + } + } +} diff --git a/src/screens/konnectors/LauncherView.spec.jsx b/src/screens/konnectors/LauncherView.spec.jsx index b1631ffa2..959a4d9be 100644 --- a/src/screens/konnectors/LauncherView.spec.jsx +++ b/src/screens/konnectors/LauncherView.spec.jsx @@ -10,6 +10,7 @@ jest.mock('@fengweichong/react-native-gzip', () => { }) jest.mock('cozy-client', () => ({ + ...jest.requireActual('cozy-client'), withClient: jest.fn().mockReturnValue({}) })) From ffd0b106d8c2e72be48c0104492604f789d3f505 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 26 Jul 2024 17:37:59 +0200 Subject: [PATCH 14/17] feat: Add react-native-mail plugin --- __tests__/jestSetupFile.js | 8 ++++++++ ios/Podfile.lock | 12 ++++++++++++ package.json | 2 ++ yarn.lock | 27 ++++++++++++++++++++++++++- 4 files changed, 48 insertions(+), 1 deletion(-) diff --git a/__tests__/jestSetupFile.js b/__tests__/jestSetupFile.js index 026e3a601..d405b1a72 100644 --- a/__tests__/jestSetupFile.js +++ b/__tests__/jestSetupFile.js @@ -140,3 +140,11 @@ jest.mock('cozy-pouch-link', () => { return new mockPouchLink() }) }) + +jest.mock('react-native-mail', () => ({ + mail: jest.fn() +})) + +jest.mock('rn-fetch-blob', () => ({ + mail: jest.fn() +})) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 0df044c93..6695dd3ea 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -509,6 +509,8 @@ PODS: - React - react-native-idle-timer (2.2.1): - React-Core + - react-native-mail (6.1.1): + - React-Core - react-native-mlkit-ocr (0.3.0): - GoogleMLKit/TextRecognition (= 2.6.0) - React @@ -648,6 +650,8 @@ PODS: - React-jsi (= 0.72.12) - React-logger (= 0.72.12) - React-perflogger (= 0.72.12) + - rn-fetch-blob (0.12.0): + - React-Core - RNBackgroundFetch (4.2.5): - React-Core - RNBackgroundGeolocation (4.16.4): @@ -776,6 +780,7 @@ DEPENDENCIES: - react-native-get-random-values (from `../node_modules/react-native-get-random-values`) - "react-native-gzip (from `../node_modules/@fengweichong/react-native-gzip`)" - react-native-idle-timer (from `../node_modules/react-native-idle-timer`) + - react-native-mail (from `../node_modules/react-native-mail`) - react-native-mlkit-ocr (from `../node_modules/react-native-mlkit-ocr`) - "react-native-netinfo (from `../node_modules/@react-native-community/netinfo`)" - react-native-print (from `../node_modules/react-native-print`) @@ -803,6 +808,7 @@ DEPENDENCIES: - React-runtimescheduler (from `../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`) - React-utils (from `../node_modules/react-native/ReactCommon/react/utils`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) + - rn-fetch-blob (from `../node_modules/rn-fetch-blob`) - RNBackgroundFetch (from `../node_modules/react-native-background-fetch`) - RNBackgroundGeolocation (from `../node_modules/react-native-background-geolocation`) - RNBootSplash (from `../node_modules/react-native-bootsplash`) @@ -937,6 +943,8 @@ EXTERNAL SOURCES: :path: "../node_modules/@fengweichong/react-native-gzip" react-native-idle-timer: :path: "../node_modules/react-native-idle-timer" + react-native-mail: + :path: "../node_modules/react-native-mail" react-native-mlkit-ocr: :path: "../node_modules/react-native-mlkit-ocr" react-native-netinfo: @@ -991,6 +999,8 @@ EXTERNAL SOURCES: :path: "../node_modules/react-native/ReactCommon/react/utils" ReactCommon: :path: "../node_modules/react-native/ReactCommon" + rn-fetch-blob: + :path: "../node_modules/rn-fetch-blob" RNBackgroundFetch: :path: "../node_modules/react-native-background-fetch" RNBackgroundGeolocation: @@ -1110,6 +1120,7 @@ SPEC CHECKSUMS: react-native-get-random-values: 21325b2244dfa6b58878f51f9aa42821e7ba3d06 react-native-gzip: 5ffb84bf191c7cd135338eca748317bc466d41a1 react-native-idle-timer: f1920a59fe776340d004ff9de13c4a6eedcc8807 + react-native-mail: 8fdcd3aef007c33a6877a18eb4cf7447a1d4ce4a react-native-mlkit-ocr: 72cdbde86f8d29cba26cf9fa0a1865fe45c8f8d6 react-native-netinfo: 48c5f79a84fbc3ba1d28a8b0d04adeda72885fa8 react-native-print: f704aef52d931bfce6d1d84351dbb5232d7ecb89 @@ -1137,6 +1148,7 @@ SPEC CHECKSUMS: React-runtimescheduler: 8aea338c561b2175f47018124c076d89d3808d30 React-utils: 9a24cb88f950d1020ee55bddacbc8c16a611e2dc ReactCommon: 76843a9bb140596351ac2786257ac9fe60cafabb + rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba RNBackgroundFetch: 2f800a04434620db15ede2e8f21886608a2d1743 RNBackgroundGeolocation: 7df16548756b443aac809663cba8a4e03f0b8732 RNBootSplash: 4844706cbb56a3270556c9b94e59dedadccd47e4 diff --git a/package.json b/package.json index 8b60fc3e6..ce11d175a 100644 --- a/package.json +++ b/package.json @@ -108,6 +108,7 @@ "react-native-ios11-devicecheck": "https://github.com/cozy/react-native-devicecheck#app-attest-v0.1", "react-native-keychain": "^8.0.0", "react-native-localize": "2.2.6", + "react-native-mail": "^6.1.1", "react-native-mask-input": "1.2.1", "react-native-mlkit-ocr": "^0.3.0", "react-native-permissions": "^3.9.3", @@ -128,6 +129,7 @@ "react-scripts": "4.0.3", "redux-logger": "3.0.6", "redux-persist": "^6.0.0", + "rn-fetch-blob": "^0.12.0", "rn-flipper-async-storage-advanced": "^1.0.4", "semver": "^7.3.2" }, diff --git a/yarn.lock b/yarn.lock index 040dd2df6..247e0c8a2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7167,7 +7167,7 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-64@^0.1.0: +base-64@0.1.0, base-64@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/base-64/-/base-64-0.1.0.tgz#780a99c84e7d600260361511c4877613bf24f6bb" integrity sha1-eAqZyE59YAJgNhURxId2E78k9rs= @@ -11042,6 +11042,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.6.tgz#211bafaf49e525b8cd93260d14ab136152b3f57a" + integrity sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + glob@7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -17361,6 +17373,11 @@ react-native-localize@2.2.6: resolved "https://registry.yarnpkg.com/react-native-localize/-/react-native-localize-2.2.6.tgz#484f8c700bc629f230066e819265f80f6dd3ef58" integrity sha512-EZETlC1ZlW/4g6xfsNCwAkAw5BDL2A6zk/08JjFR/GRGxYuKRD7iP1hHn1+h6DEu+xROjPpoNeXfMER2vkTVIQ== +react-native-mail@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/react-native-mail/-/react-native-mail-6.1.1.tgz#f1b1f8034c84d2510a93e4a2a795f0db5a13595e" + integrity sha512-pTs180wwyh7hN/iyTC9SfOX579U4YhDlHOLxi47IGvhPJENqO/QFdBq+wWKxyhNqdQuVSy+LoeIxLreWnIeYmg== + react-native-mask-input@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/react-native-mask-input/-/react-native-mask-input-1.2.1.tgz#2f01683844ded3693d0d845bd1beeb2b8367f2e2" @@ -18153,6 +18170,14 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rn-fetch-blob@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/rn-fetch-blob/-/rn-fetch-blob-0.12.0.tgz#ec610d2f9b3f1065556b58ab9c106eeb256f3cba" + integrity sha512-+QnR7AsJ14zqpVVUbzbtAjq0iI8c9tCg49tIoKO2ezjzRunN7YL6zFSFSWZm6d+mE/l9r+OeDM3jmb2tBb2WbA== + dependencies: + base-64 "0.1.0" + glob "7.0.6" + rn-flipper-async-storage-advanced@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/rn-flipper-async-storage-advanced/-/rn-flipper-async-storage-advanced-1.0.4.tgz#ca3d0c315a75f379fef3771cc6ee3bef2d774265" From 8ceea9b4a6d25d45aff9de8ce3bae11f81352c12 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 26 Jul 2024 18:35:44 +0200 Subject: [PATCH 15/17] feat: Allow to send Pouch databases through email for debug purpose By adding offline support through PouchDB, we expect database related bugs to happens in the future In order to ease debugging them, we want to allow exploring the local PouchDB files The easier way is to add the ability to extract them from the device and send them through email to cozy's support team --- src/hooks/useAppBootstrap.js | 5 + src/hooks/useAppBootstrap.spec.js | 1 + src/pouchdb/deeplinkHandler.ts | 23 +++++ src/pouchdb/sendDbByEmail.ts | 146 ++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+) create mode 100644 src/pouchdb/deeplinkHandler.ts create mode 100644 src/pouchdb/sendDbByEmail.ts diff --git a/src/hooks/useAppBootstrap.js b/src/hooks/useAppBootstrap.js index c00d813a9..f2921b993 100644 --- a/src/hooks/useAppBootstrap.js +++ b/src/hooks/useAppBootstrap.js @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react' import { deconstructCozyWebLinkWithSlug } from 'cozy-client' import { handleLogsDeepLink } from '/app/domain/logger/deeplinkHandler' +import { handleDbDeepLink } from '/pouchdb/deeplinkHandler' import { SentryCustomTags, setSentryTag } from '/libs/monitoring/Sentry' import { manageIconCache } from '/libs/functions/iconTable' import { getDefaultIconParams } from '/libs/functions/openApp' @@ -160,6 +161,10 @@ export const useAppBootstrap = client => { return } + if (handleDbDeepLink(url, client)) { + return + } + if (!client) { const action = parseOnboardLink(url) diff --git a/src/hooks/useAppBootstrap.spec.js b/src/hooks/useAppBootstrap.spec.js index 799fd4c5f..64935073d 100644 --- a/src/hooks/useAppBootstrap.spec.js +++ b/src/hooks/useAppBootstrap.spec.js @@ -50,6 +50,7 @@ jest.mock('/libs/RootNavigation', () => ({ jest.mock('./useSplashScreen', () => ({ useSplashScreen: () => ({ hideSplashScreen: mockHideSplashScreen }) })) +jest.mock('/app/theme/SplashScreenService', () => ({})) jest.mock('/libs/functions/openApp', () => ({ getDefaultIconParams: jest.fn().mockReturnValue({}) diff --git a/src/pouchdb/deeplinkHandler.ts b/src/pouchdb/deeplinkHandler.ts new file mode 100644 index 000000000..0867436a6 --- /dev/null +++ b/src/pouchdb/deeplinkHandler.ts @@ -0,0 +1,23 @@ +import CozyClient from 'cozy-client' + +import strings from '/constants/strings.json' +import { sendDbByEmail } from '/pouchdb/sendDbByEmail' + +export const handleDbDeepLink = (url: string, client?: CozyClient): boolean => { + if (isSendDbDeepLink(url)) { + void sendDbByEmail(client) + + return true + } + + return false +} + +const isSendDbDeepLink = (url: string): boolean => { + const deepLinks = [ + `${strings.COZY_SCHEME}senddb`, + `${strings.UNIVERSAL_LINK_BASE}/senddb` + ] + + return deepLinks.includes(url.toLowerCase()) +} diff --git a/src/pouchdb/sendDbByEmail.ts b/src/pouchdb/sendDbByEmail.ts new file mode 100644 index 000000000..e13ad654a --- /dev/null +++ b/src/pouchdb/sendDbByEmail.ts @@ -0,0 +1,146 @@ +import { Alert, PermissionsAndroid, Platform } from 'react-native' +import Mailer from 'react-native-mail' +import RNFS from 'react-native-fs' +import RNFetchBlob from 'rn-fetch-blob' +import DeviceInfo from 'react-native-device-info' + +import type CozyClient from 'cozy-client' +import Minilog from 'cozy-minilog' + +import { fetchSupportMail } from '/app/domain/logger/supportEmail' +import { + hideSplashScreen, + showSplashScreen, + splashScreens +} from '/app/theme/SplashScreenService' +import { getInstanceAndFqdnFromClient } from '/libs/client' +import { getErrorMessage } from '/libs/functions/getErrorMessage' + +const log = Minilog('🗒️ DB Mailer') + +export const sendDbByEmail = async (client?: CozyClient): Promise => { + log.info('Send DB by email') + + if (!client) { + log.info('SendDbByEmail called with no client, return') + return + } + + try { + const permission = PermissionsAndroid.PERMISSIONS.WRITE_EXTERNAL_STORAGE + await PermissionsAndroid.request(permission) + + const supportEmail = await fetchSupportMail(client) + + const { fqdn } = getInstanceAndFqdnFromClient(client) + + const instance = client.getStackClient().uri ?? 'not logged app' + + const subject = `DB files for ${instance}` + + const files = await RNFS.readDir(RNFS.DocumentDirectoryPath) + + const dbFiles = files.filter(f => f.name.startsWith(`${fqdn}_`)) + + const externalFiles = [] + for (const dbFile of dbFiles) { + const dirs = RNFetchBlob.fs.dirs + + const internalPath = dbFile.path + + if (Platform.OS === 'android') { + const date = Number(new Date()) + const externalPath = `${dirs.DCIMDir}/DbFile_${dbFile.name}${date}.sqlite` + + await RNFS.copyFile(internalPath, externalPath) + + externalFiles.push({ + path: externalPath + }) + } else { + externalFiles.push({ + path: dbFile.path, + type: 'pdf' // there is no compatible MIME type, so we use PDF one as replacement, this should change nothing expect the email aspect + }) + } + } + + await showSplashScreen(splashScreens.SEND_LOG_EMAIL) + log.info('Start email intent', externalFiles) + await sendMailPromise(subject, supportEmail, externalFiles).catch( + (errorData: sendMailError) => { + const { error, event } = errorData + Alert.alert( + error, + event, + [ + { + text: 'Ok', + onPress: (): void => log.debug('OK: Email Error Response') + }, + { + text: 'Cancel', + onPress: (): void => log.debug('CANCEL: Email Error Response') + } + ], + { cancelable: true } + ) + } + ) + log.info('Did finish email intent') + await hideSplashScreen(splashScreens.SEND_LOG_EMAIL) + } catch (error) { + const errorMessage = getErrorMessage(error) + log.error('Error while trying to send DB email', errorMessage) + } +} + +const sendMailPromise = ( + subject: string, + email: string, + attachments: Attachment[] +): Promise => { + return new Promise((resolve, reject) => { + Mailer.mail( + { + subject: subject, + recipients: [email], + body: buildMessageBody(), + isHTML: true, + attachments: attachments + }, + (error, event) => { + if (error) { + reject({ error, event }) + } else { + resolve() + } + } + ) + }) +} + +const buildMessageBody = (): string => { + const appVersion = DeviceInfo.getVersion() + const appBuild = DeviceInfo.getBuildNumber() + const bundle = DeviceInfo.getBundleId() + const deviceBrand = DeviceInfo.getBrand() + const deviceModel = DeviceInfo.getModel() + const os = DeviceInfo.getSystemName() + const version = DeviceInfo.getSystemVersion() + + const appInfo = `App info: ${appVersion} (${appBuild})` + const bundleInfo = `App bundle: ${bundle}` + const deviceInfo = `Device info: ${deviceBrand} ${deviceModel} ${os} ${version}` + + return `${appInfo}\n${bundleInfo}\n${deviceInfo}` +} + +interface sendMailError { + error: string + event?: string +} + +interface Attachment { + path: string +} From fa2d7276009153fad44a17432e9b4ed32247a519 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Tue, 30 Jul 2024 20:35:01 +0200 Subject: [PATCH 16/17] feat: Declare offline support in cozy-apps injected metadata --- src/components/webviews/jsInteractions/jsCozyInjection.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/webviews/jsInteractions/jsCozyInjection.ts b/src/components/webviews/jsInteractions/jsCozyInjection.ts index 6c1374da6..400a5ea9d 100644 --- a/src/components/webviews/jsInteractions/jsCozyInjection.ts +++ b/src/components/webviews/jsInteractions/jsCozyInjection.ts @@ -17,6 +17,7 @@ const makeMetadata = (routeName?: string): string => { return JSON.stringify({ immersive: routeName ? immersiveRoutes.includes(routeName) : false, navbarHeight, + offline_available: true, platform: Platform, routeName, statusBarHeight, From 749ef4009f9dd5ff0748ec23991f7fa327f50ea8 Mon Sep 17 00:00:00 2001 From: Ldoppea Date: Fri, 13 Sep 2024 17:03:18 +0200 Subject: [PATCH 17/17] feat: Prevent local PouchDB modification to be replicated to remote DB For now we don't want to replicate local changes into remote PouchDB as we first want to ensure everything works as expected locally before activating two-way replication in the future --- src/pouchdb/getLinks.ts | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/pouchdb/getLinks.ts b/src/pouchdb/getLinks.ts index 5ad1d6abe..b4ffe5781 100644 --- a/src/pouchdb/getLinks.ts +++ b/src/pouchdb/getLinks.ts @@ -30,7 +30,17 @@ export const getLinks = (): CozyLink[] => { doctypes: offlineDoctypes, initialSync: true, platform: platformReactNative, - ignoreWarmup: true + ignoreWarmup: true, + doctypesReplicationOptions: Object.fromEntries( + offlineDoctypes.map(doctype => { + return [ + doctype, + { + strategy: 'fromRemote' + } + ] + }) + ) } const stackLink = new StackLink({