diff --git a/.changeset/six-papayas-fall.md b/.changeset/six-papayas-fall.md new file mode 100644 index 000000000..12cff4c2f --- /dev/null +++ b/.changeset/six-papayas-fall.md @@ -0,0 +1,8 @@ +--- +"@onflow/fcl-react-native": minor +"@onflow/react-native-sdk": minor +"@onflow/react-sdk": minor +"@onflow/demo": minor +--- + +Added react-native-sdk package, similar to react-sdk but for react-native applications. It fully supports all the same hooks available in react-sdk, plus the connect and profile components. It leverages fcl-react-native for managing blockchain interactions and it's compatible to both react-native and expo applications. diff --git a/package-lock.json b/package-lock.json index f7099273e..55f20f9a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -126,13 +126,13 @@ } }, "node_modules/@babel/generator": { - "version": "7.28.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.3.tgz", - "integrity": "sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz", + "integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==", "license": "MIT", "dependencies": { - "@babel/parser": "^7.28.3", - "@babel/types": "^7.28.2", + "@babel/parser": "^7.28.5", + "@babel/types": "^7.28.5", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -346,7 +346,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "license": "MIT", "engines": { "node": ">=6.9.0" @@ -396,12 +398,12 @@ } }, "node_modules/@babel/parser": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.4.tgz", - "integrity": "sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz", + "integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==", "license": "MIT", "dependencies": { - "@babel/types": "^7.28.4" + "@babel/types": "^7.28.5" }, "bin": { "parser": "bin/babel-parser.js" @@ -531,7 +533,6 @@ "node_modules/@babel/plugin-proposal-export-default-from": { "version": "7.25.8", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -545,7 +546,6 @@ "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { "version": "7.18.6", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.18.6", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" @@ -608,7 +608,6 @@ "node_modules/@babel/plugin-proposal-optional-chaining": { "version": "7.21.0", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2", "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", @@ -695,7 +694,6 @@ "node_modules/@babel/plugin-syntax-dynamic-import": { "version": "7.8.3", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.8.0" }, @@ -706,7 +704,6 @@ "node_modules/@babel/plugin-syntax-export-default-from": { "version": "7.25.7", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -720,7 +717,6 @@ "node_modules/@babel/plugin-syntax-flow": { "version": "7.25.7", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7" }, @@ -1133,7 +1129,6 @@ "node_modules/@babel/plugin-transform-flow-strip-types": { "version": "7.25.7", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/plugin-syntax-flow": "^7.25.7" @@ -1823,7 +1818,6 @@ "node_modules/@babel/preset-flow": { "version": "7.25.7", "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.25.7", "@babel/helper-validator-option": "^7.25.7", @@ -1886,7 +1880,6 @@ "node_modules/@babel/register": { "version": "7.25.7", "license": "MIT", - "peer": true, "dependencies": { "clone-deep": "^4.0.1", "find-cache-dir": "^2.0.0", @@ -1904,7 +1897,6 @@ "node_modules/@babel/register/node_modules/make-dir": { "version": "2.1.0", "license": "MIT", - "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -1916,7 +1908,6 @@ "node_modules/@babel/register/node_modules/pify": { "version": "4.0.1", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -1924,7 +1915,6 @@ "node_modules/@babel/register/node_modules/semver": { "version": "5.7.2", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver" } @@ -1971,14 +1961,34 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse--for-generate-function-map": { + "name": "@babel/traverse", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz", + "integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.5", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.5", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.5", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { - "version": "7.28.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.4.tgz", - "integrity": "sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz", + "integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==", "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.27.1" + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -5975,7 +5985,6 @@ "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", "license": "ISC", - "peer": true, "engines": { "node": ">=12" } @@ -6196,7 +6205,6 @@ "node_modules/@jest/create-cache-key-function": { "version": "29.7.0", "license": "MIT", - "peer": true, "dependencies": { "@jest/types": "^29.6.3" }, @@ -9001,6 +9009,10 @@ "resolved": "packages/react-core", "link": true }, + "node_modules/@onflow/react-native-sdk": { + "resolved": "packages/react-native-sdk", + "link": true + }, "node_modules/@onflow/react-sdk": { "resolved": "packages/react-sdk", "link": true @@ -10834,8 +10846,792 @@ "@babel/plugin-transform-typescript": "^7.25.2", "@babel/plugin-transform-unicode-regex": "^7.24.7", "@babel/template": "^7.25.0", - "@react-native/babel-plugin-codegen": "0.79.6", - "babel-plugin-syntax-hermes-parser": "0.25.1", + "@react-native/babel-plugin-codegen": "0.79.6", + "babel-plugin-syntax-hermes-parser": "0.25.1", + "babel-plugin-transform-flow-enums": "^0.0.2", + "react-refresh": "^0.14.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/codegen": { + "version": "0.79.6", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.6.tgz", + "integrity": "sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.25.1", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.76.9.tgz", + "integrity": "sha512-08jx8ixCjjd4jNQwNpP8yqrjrDctN2qvPPlf6ebz1OJQk8e1sbUl3wVn1zhhMvWrYcaraDnatPb5uCPq+dn3NQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/dev-middleware": "0.76.9", + "@react-native/metro-babel-transformer": "0.76.9", + "chalk": "^4.0.0", + "execa": "^5.1.1", + "invariant": "^2.2.4", + "metro": "^0.81.0", + "metro-config": "^0.81.0", + "metro-core": "^0.81.0", + "node-fetch": "^2.2.0", + "readline": "^1.3.0", + "semver": "^7.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@react-native-community/cli": "*" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + } + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/@react-native/debugger-frontend": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.76.9.tgz", + "integrity": "sha512-0Ru72Bm066xmxFuOXhhvrryxvb57uI79yDSFf+hxRpktkC98NMuRenlJhslMrbJ6WjCu1vOe/9UjWNYyxXTRTA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/@react-native/dev-middleware": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.76.9.tgz", + "integrity": "sha512-xkd3C3dRcmZLjFTEAOvC14q3apMLouIvJViCZY/p1EfCMrNND31dgE1dYrLTiI045WAWMt5bD15i6f7dE2/QWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.76.9", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "selfsigned": "^2.4.1", + "serve-static": "^1.13.1", + "ws": "^6.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/community-cli-plugin/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/community-cli-plugin/node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/community-cli-plugin/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha512-eZ5H8rcgYazHbKC3PG4ClHNykCSxtAhxSSEM+2mb+7evD2CKF5V7c0dNum7AdpDh0ZdICwZY9sRSn8f+KH96sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.81.5.tgz", + "integrity": "sha512-YpFF0DDDpDVygeca2mAn7K0+us+XKmiGk4rIYMz/CRdjFoCGqAei/IQSpV0UrGfQbToSugpMQeQJveaWSH88Hg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "@babel/types": "^7.25.2", + "accepts": "^1.3.7", + "chalk": "^4.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.25.1", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.81.5", + "metro-cache": "0.81.5", + "metro-cache-key": "0.81.5", + "metro-config": "0.81.5", + "metro-core": "0.81.5", + "metro-file-map": "0.81.5", + "metro-resolver": "0.81.5", + "metro-runtime": "0.81.5", + "metro-source-map": "0.81.5", + "metro-symbolicate": "0.81.5", + "metro-transform-plugins": "0.81.5", + "metro-transform-worker": "0.81.5", + "mime-types": "^2.1.27", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-babel-transformer": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.81.5.tgz", + "integrity": "sha512-oKCQuajU5srm+ZdDcFg86pG/U8hkSjBlkyFjz380SZ4TTIiI5F+OQB830i53D8hmqmcosa4wR/pnKv8y4Q3dLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.25.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-cache": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.81.5.tgz", + "integrity": "sha512-wOsXuEgmZMZ5DMPoz1pEDerjJ11AuMy9JifH4yNW7NmWS0ghCRqvDxk13LsElzLshey8C+my/tmXauXZ3OqZgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "metro-core": "0.81.5" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-cache-key": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.81.5.tgz", + "integrity": "sha512-lGWnGVm1UwO8faRZ+LXQUesZSmP1LOg14OVR+KNPBip8kbMECbQJ8c10nGesw28uQT7AE0lwQThZPXlxDyCLKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-config": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.81.5.tgz", + "integrity": "sha512-oDRAzUvj6RNRxratFdcVAqtAsg+T3qcKrGdqGZFUdwzlFJdHGR9Z413sW583uD2ynsuOjA2QB6US8FdwiBdNKg==", + "dev": true, + "license": "MIT", + "dependencies": { + "connect": "^3.6.5", + "cosmiconfig": "^5.0.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.81.5", + "metro-cache": "0.81.5", + "metro-core": "0.81.5", + "metro-runtime": "0.81.5" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-core": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.81.5.tgz", + "integrity": "sha512-+2R0c8ByfV2N7CH5wpdIajCWa8escUFd8TukfoXyBq/vb6yTCsznoA25FhNXJ+MC/cz1L447Zj3vdUfCXIZBwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.81.5" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-file-map": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.81.5.tgz", + "integrity": "sha512-mW1PKyiO3qZvjeeVjj1brhkmIotObA3/9jdbY1fQQYvEWM6Ml7bN/oJCRDGn2+bJRlG+J8pwyJ+DgdrM4BsKyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^2.2.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-minify-terser": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.81.5.tgz", + "integrity": "sha512-/mn4AxjANnsSS3/Bb+zA1G5yIS5xygbbz/OuPaJYs0CPcZCaWt66D+65j4Ft/nJkffUxcwE9mk4ubpkl3rjgtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-resolver": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.81.5.tgz", + "integrity": "sha512-6BX8Nq3g3go3FxcyXkVbWe7IgctjDTk6D9flq+P201DfHHQ28J+DWFpVelFcrNTn4tIfbP/Bw7u/0g2BGmeXfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-runtime": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.5.tgz", + "integrity": "sha512-M/Gf71ictUKP9+77dV/y8XlAWg7xl76uhU7ggYFUwEdOHHWPG6gLBr1iiK0BmTjPFH8yRo/xyqMli4s3oGorPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-source-map": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.5.tgz", + "integrity": "sha512-Jz+CjvCKLNbJZYJTBeN3Kq9kIJf6b61MoLBdaOQZJ5Ajhw6Pf95Nn21XwA8BwfUYgajsi6IXsp/dTZsYJbN00Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.81.5", + "nullthrows": "^1.1.1", + "ob1": "0.81.5", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-symbolicate": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.81.5.tgz", + "integrity": "sha512-X3HV3n3D6FuTE11UWFICqHbFMdTavfO48nXsSpnNGFkUZBexffu0Xd+fYKp+DJLNaQr3S+lAs8q9CgtDTlRRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.81.5", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-transform-plugins": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.81.5.tgz", + "integrity": "sha512-MmHhVx/1dJC94FN7m3oHgv5uOjKH8EX8pBeu1pnPMxbJrx6ZuIejO0k84zTSaQTZ8RxX1wqwzWBpXAWPjEX8mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.3", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro-transform-worker": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.81.5.tgz", + "integrity": "sha512-lUFyWVHa7lZFRSLJEv+m4jH8WrR5gU7VIjUlg4XmxQfV8ngY4V10ARKynLhMYPeQGl7Qvf+Ayg0eCZ272YZ4Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.25.0", + "@babel/parser": "^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "metro": "0.81.5", + "metro-babel-transformer": "0.81.5", + "metro-cache": "0.81.5", + "metro-cache-key": "0.81.5", + "metro-minify-terser": "0.81.5", + "metro-source-map": "0.81.5", + "metro-transform-plugins": "0.81.5", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/metro/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ob1": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.81.5.tgz", + "integrity": "sha512-iNpbeXPLmaiT9I5g16gFFFjsF3sGxLpYG2EGP3dfFB4z+l9X60mp/yRzStHhMtuNt8qmf7Ww80nOPQHngHhnIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", + "dev": true, + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha512-GnlH6vxLymXJNMBo7XP1fJIzBFbdYt49CuTwmB/6N53t+kMPRMFKz783LlQ4tv28XoQfMWinAJX6WCGf2IlaIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.79.6", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.6.tgz", + "integrity": "sha512-lIK/KkaH7ueM22bLO0YNaQwZbT/oeqhaghOvmZacaNVbJR1Cdh/XAqjT8FgCS+7PUnbxA8B55NYNKGZG3O2pYw==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.79.6", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.6.tgz", + "integrity": "sha512-BK3GZBa9c7XSNR27EDRtxrgyyA3/mf1j3/y+mPk7Ac0Myu85YNrXnC9g3mL5Ytwo0g58TKrAIgs1fF2Q5Mn6mQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.79.6", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.2.0", + "connect": "^3.6.5", + "debug": "^2.2.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^6.2.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-native/dev-middleware/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "license": "MIT", + "peer": true, + "dependencies": { + "async-limiter": "~1.0.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.72.11", + "license": "MIT", + "peer": true + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.72.1", + "license": "MIT", + "peer": true + }, + "node_modules/@react-native/metro-babel-transformer": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/metro-babel-transformer/-/metro-babel-transformer-0.76.9.tgz", + "integrity": "sha512-HGq11347UHNiO/NvVbAO35hQCmH8YZRs7in7nVq7SL99pnpZK4WXwLdAXmSuwz5uYqOuwnKYDlpadz8fkE94Mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@react-native/babel-preset": "0.76.9", + "hermes-parser": "0.23.1", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/core": "*" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-plugin-codegen": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/babel-plugin-codegen/-/babel-plugin-codegen-0.76.9.tgz", + "integrity": "sha512-vxL/vtDEIYHfWKm5oTaEmwcnNGsua/i9OjIxBDBFiJDu5i5RU3bpmDiXQm/bJxrJNPRp5lW0I0kpGihVhnMAIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@react-native/codegen": "0.76.9" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/babel-preset": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/babel-preset/-/babel-preset-0.76.9.tgz", + "integrity": "sha512-TbSeCplCM6WhL3hR2MjC/E1a9cRnMLz7i767T7mP90oWkklEjyPxWl+0GGoVGnJ8FC/jLUupg/HvREKjjif6lw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/plugin-proposal-export-default-from": "^7.24.7", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-default-from": "^7.24.7", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-transform-arrow-functions": "^7.24.7", + "@babel/plugin-transform-async-generator-functions": "^7.25.4", + "@babel/plugin-transform-async-to-generator": "^7.24.7", + "@babel/plugin-transform-block-scoping": "^7.25.0", + "@babel/plugin-transform-class-properties": "^7.25.4", + "@babel/plugin-transform-classes": "^7.25.4", + "@babel/plugin-transform-computed-properties": "^7.24.7", + "@babel/plugin-transform-destructuring": "^7.24.8", + "@babel/plugin-transform-flow-strip-types": "^7.25.2", + "@babel/plugin-transform-for-of": "^7.24.7", + "@babel/plugin-transform-function-name": "^7.25.1", + "@babel/plugin-transform-literals": "^7.25.2", + "@babel/plugin-transform-logical-assignment-operators": "^7.24.7", + "@babel/plugin-transform-modules-commonjs": "^7.24.8", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.24.7", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.24.7", + "@babel/plugin-transform-numeric-separator": "^7.24.7", + "@babel/plugin-transform-object-rest-spread": "^7.24.7", + "@babel/plugin-transform-optional-catch-binding": "^7.24.7", + "@babel/plugin-transform-optional-chaining": "^7.24.8", + "@babel/plugin-transform-parameters": "^7.24.7", + "@babel/plugin-transform-private-methods": "^7.24.7", + "@babel/plugin-transform-private-property-in-object": "^7.24.7", + "@babel/plugin-transform-react-display-name": "^7.24.7", + "@babel/plugin-transform-react-jsx": "^7.25.2", + "@babel/plugin-transform-react-jsx-self": "^7.24.7", + "@babel/plugin-transform-react-jsx-source": "^7.24.7", + "@babel/plugin-transform-regenerator": "^7.24.7", + "@babel/plugin-transform-runtime": "^7.24.7", + "@babel/plugin-transform-shorthand-properties": "^7.24.7", + "@babel/plugin-transform-spread": "^7.24.7", + "@babel/plugin-transform-sticky-regex": "^7.24.7", + "@babel/plugin-transform-typescript": "^7.25.2", + "@babel/plugin-transform-unicode-regex": "^7.24.7", + "@babel/template": "^7.25.0", + "@react-native/babel-plugin-codegen": "0.76.9", + "babel-plugin-syntax-hermes-parser": "^0.25.1", "babel-plugin-transform-flow-enums": "^0.0.2", "react-refresh": "^0.14.0" }, @@ -10846,18 +11642,19 @@ "@babel/core": "*" } }, - "node_modules/@react-native/codegen": { - "version": "0.79.6", - "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.79.6.tgz", - "integrity": "sha512-iRBX8Lgbqypwnfba7s6opeUwVyaR23mowh9ILw7EcT2oLz3RqMmjJdrbVpWhGSMGq2qkPfqAH7bhO8C7O+xfjQ==", + "node_modules/@react-native/metro-babel-transformer/node_modules/@react-native/codegen": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.76.9.tgz", + "integrity": "sha512-AzlCHMTKrAVC2709V4ZGtBXmGVtWTpWm3Ruv5vXcd3/anH4mGucfJ4rjbWKdaYQJMpXa3ytGomQrsIsT/s8kgA==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "@babel/core": "^7.25.2", "@babel/parser": "^7.25.3", "glob": "^7.1.1", - "hermes-parser": "0.25.1", + "hermes-parser": "0.23.1", "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", "nullthrows": "^1.1.1", "yargs": "^17.6.2" }, @@ -10865,79 +11662,26 @@ "node": ">=18" }, "peerDependencies": { - "@babel/core": "*" - } - }, - "node_modules/@react-native/debugger-frontend": { - "version": "0.79.6", - "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.79.6.tgz", - "integrity": "sha512-lIK/KkaH7ueM22bLO0YNaQwZbT/oeqhaghOvmZacaNVbJR1Cdh/XAqjT8FgCS+7PUnbxA8B55NYNKGZG3O2pYw==", - "license": "BSD-3-Clause", - "peer": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/dev-middleware": { - "version": "0.79.6", - "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.79.6.tgz", - "integrity": "sha512-BK3GZBa9c7XSNR27EDRtxrgyyA3/mf1j3/y+mPk7Ac0Myu85YNrXnC9g3mL5Ytwo0g58TKrAIgs1fF2Q5Mn6mQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@isaacs/ttlcache": "^1.4.1", - "@react-native/debugger-frontend": "0.79.6", - "chrome-launcher": "^0.15.2", - "chromium-edge-launcher": "^0.2.0", - "connect": "^3.6.5", - "debug": "^2.2.0", - "invariant": "^2.2.4", - "nullthrows": "^1.1.1", - "open": "^7.0.3", - "serve-static": "^1.16.2", - "ws": "^6.2.3" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@react-native/dev-middleware/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", - "peer": true, - "dependencies": { - "ms": "2.0.0" + "@babel/preset-env": "^7.1.6" } }, - "node_modules/@react-native/dev-middleware/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", + "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", + "dev": true, + "license": "MIT" }, - "node_modules/@react-native/dev-middleware/node_modules/ws": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", - "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "node_modules/@react-native/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", + "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", + "dev": true, "license": "MIT", - "peer": true, "dependencies": { - "async-limiter": "~1.0.0" + "hermes-estree": "0.23.1" } }, - "node_modules/@react-native/gradle-plugin": { - "version": "0.72.11", - "license": "MIT", - "peer": true - }, - "node_modules/@react-native/js-polyfills": { - "version": "0.72.1", - "license": "MIT", - "peer": true - }, "node_modules/@react-native/normalize-colors": { "version": "0.79.5", "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.79.5.tgz", @@ -12314,6 +13058,16 @@ "undici-types": "~5.26.4" } }, + "node_modules/@types/node-forge": { + "version": "1.3.14", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.14.tgz", + "integrity": "sha512-mhVF2BnD4BO+jtOp7z1CdzaK4mbuK0LLQYAvdOLqHTavxFNq4zA1EmYkpnFjP8HOUzedfQkRnp0E2ulSAYSzAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/normalize-package-data": { "version": "2.4.4", "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", @@ -13581,7 +14335,6 @@ "node_modules/accepts": { "version": "1.3.8", "license": "MIT", - "peer": true, "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -13693,8 +14446,7 @@ }, "node_modules/anser": { "version": "1.4.10", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ansi-colors": { "version": "4.1.3", @@ -13866,13 +14618,11 @@ }, "node_modules/asap": { "version": "2.0.6", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ast-types": { "version": "0.15.2", "license": "MIT", - "peer": true, "dependencies": { "tslib": "^2.0.1" }, @@ -13882,8 +14632,7 @@ }, "node_modules/ast-types/node_modules/tslib": { "version": "2.8.1", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/astral-regex": { "version": "1.0.0", @@ -13899,8 +14648,7 @@ }, "node_modules/async-limiter": { "version": "1.0.1", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/async-mutex": { "version": "0.2.6", @@ -14006,7 +14754,6 @@ "node_modules/babel-core": { "version": "7.0.0-bridge.0", "license": "MIT", - "peer": true, "peerDependencies": { "@babel/core": "^7.0.0-0" } @@ -14184,7 +14931,6 @@ "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.25.1.tgz", "integrity": "sha512-IVNpGzboFLfXZUAwkLFcI/bnqVbwky0jP3eBno4HKtqvQJAHBLdgxiG6lQ4to0+Q/YCN3PO0od5NZwIKyY4REQ==", "license": "MIT", - "peer": true, "dependencies": { "hermes-parser": "0.25.1" } @@ -14197,7 +14943,6 @@ "node_modules/babel-plugin-transform-flow-enums": { "version": "0.0.2", "license": "MIT", - "peer": true, "dependencies": { "@babel/plugin-syntax-flow": "^7.12.1" } @@ -14900,7 +15645,6 @@ "node_modules/caller-callsite": { "version": "2.0.0", "license": "MIT", - "peer": true, "dependencies": { "callsites": "^2.0.0" }, @@ -14911,7 +15655,6 @@ "node_modules/caller-callsite/node_modules/callsites": { "version": "2.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -14919,7 +15662,6 @@ "node_modules/caller-path": { "version": "2.0.0", "license": "MIT", - "peer": true, "dependencies": { "caller-callsite": "^2.0.0" }, @@ -15130,7 +15872,6 @@ "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -15149,7 +15890,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -15170,7 +15910,6 @@ "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.2.0.tgz", "integrity": "sha512-JfJjUnq25y9yg4FABRRVPmBGWPZZi+AQXT4mxupb67766/0UlhG8PAZCz6xzEMXTbW3CsSoE8PcCWA49n35mKg==", "license": "Apache-2.0", - "peer": true, "dependencies": { "@types/node": "*", "escape-string-regexp": "^4.0.0", @@ -15185,7 +15924,6 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "license": "MIT", - "peer": true, "engines": { "node": ">=10" }, @@ -15198,7 +15936,6 @@ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", "license": "MIT", - "peer": true, "bin": { "mkdirp": "bin/cmd.js" }, @@ -15637,7 +16374,6 @@ "node_modules/connect": { "version": "3.7.0", "license": "MIT", - "peer": true, "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -15651,15 +16387,13 @@ "node_modules/connect/node_modules/debug": { "version": "2.6.9", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } }, "node_modules/connect/node_modules/ms": { "version": "2.0.0", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/console-control-strings": { "version": "1.1.0", @@ -16190,7 +16924,9 @@ "license": "MIT" }, "node_modules/csstype": { - "version": "3.1.3", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, "node_modules/dargs": { @@ -16412,7 +17148,6 @@ "node_modules/depd": { "version": "2.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -16467,7 +17202,6 @@ "node_modules/destroy": { "version": "1.2.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -16709,8 +17443,7 @@ }, "node_modules/ee-first": { "version": "1.1.1", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/ejs": { "version": "3.1.10", @@ -16765,7 +17498,6 @@ "node_modules/encodeurl": { "version": "1.0.2", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -16852,7 +17584,6 @@ }, "node_modules/entities": { "version": "4.5.0", - "dev": true, "license": "BSD-2-Clause", "engines": { "node": ">=0.12" @@ -16908,7 +17639,6 @@ "node_modules/error-stack-parser": { "version": "2.1.4", "license": "MIT", - "peer": true, "dependencies": { "stackframe": "^1.3.4" } @@ -17044,8 +17774,7 @@ }, "node_modules/escape-html": { "version": "1.0.3", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/escape-string-regexp": { "version": "1.0.5", @@ -17483,7 +18212,6 @@ "node_modules/etag": { "version": "1.8.1", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -17762,6 +18490,17 @@ "react-native": "*" } }, + "node_modules/expo-clipboard": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/expo-clipboard/-/expo-clipboard-7.1.5.tgz", + "integrity": "sha512-TCANUGOxouoJXxKBW5ASJl2WlmQLGpuZGemDCL2fO5ZMl57DGTypUmagb0CVUFxDl0yAtFIcESd78UsF9o64aw==", + "license": "MIT", + "peerDependencies": { + "expo": "*", + "react": "*", + "react-native": "*" + } + }, "node_modules/expo-constants": { "version": "17.1.7", "resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-17.1.7.tgz", @@ -18481,7 +19220,6 @@ "node_modules/finalhandler": { "version": "1.1.2", "license": "MIT", - "peer": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -18498,20 +19236,17 @@ "node_modules/finalhandler/node_modules/debug": { "version": "2.6.9", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } }, "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/find-cache-dir": { "version": "2.1.0", "license": "MIT", - "peer": true, "dependencies": { "commondir": "^1.0.1", "make-dir": "^2.0.0", @@ -18524,7 +19259,6 @@ "node_modules/find-cache-dir/node_modules/find-up": { "version": "3.0.0", "license": "MIT", - "peer": true, "dependencies": { "locate-path": "^3.0.0" }, @@ -18535,7 +19269,6 @@ "node_modules/find-cache-dir/node_modules/locate-path": { "version": "3.0.0", "license": "MIT", - "peer": true, "dependencies": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" @@ -18547,7 +19280,6 @@ "node_modules/find-cache-dir/node_modules/make-dir": { "version": "2.1.0", "license": "MIT", - "peer": true, "dependencies": { "pify": "^4.0.1", "semver": "^5.6.0" @@ -18559,7 +19291,6 @@ "node_modules/find-cache-dir/node_modules/p-locate": { "version": "3.0.0", "license": "MIT", - "peer": true, "dependencies": { "p-limit": "^2.0.0" }, @@ -18570,7 +19301,6 @@ "node_modules/find-cache-dir/node_modules/path-exists": { "version": "3.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">=4" } @@ -18578,7 +19308,6 @@ "node_modules/find-cache-dir/node_modules/pify": { "version": "4.0.1", "license": "MIT", - "peer": true, "engines": { "node": ">=6" } @@ -18586,7 +19315,6 @@ "node_modules/find-cache-dir/node_modules/pkg-dir": { "version": "3.0.0", "license": "MIT", - "peer": true, "dependencies": { "find-up": "^3.0.0" }, @@ -18597,7 +19325,6 @@ "node_modules/find-cache-dir/node_modules/semver": { "version": "5.7.2", "license": "ISC", - "peer": true, "bin": { "semver": "bin/semver" } @@ -18647,7 +19374,6 @@ "node_modules/flow-parser": { "version": "0.206.0", "license": "MIT", - "peer": true, "engines": { "node": ">=0.4.0" } @@ -18752,7 +19478,6 @@ "node_modules/fresh": { "version": "0.5.2", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -19372,15 +20097,13 @@ "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", "integrity": "sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/hermes-parser": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.25.1.tgz", "integrity": "sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==", "license": "MIT", - "peer": true, "dependencies": { "hermes-estree": "0.25.1" } @@ -19474,7 +20197,6 @@ "node_modules/http-errors": { "version": "2.0.0", "license": "MIT", - "peer": true, "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -19489,7 +20211,6 @@ "node_modules/http-errors/node_modules/statuses": { "version": "2.0.1", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -19637,7 +20358,6 @@ "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", "license": "MIT", - "peer": true, "dependencies": { "queue": "6.0.2" }, @@ -20019,7 +20739,6 @@ "node_modules/is-directory": { "version": "0.3.1", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -22259,18 +22978,15 @@ }, "node_modules/jsc-android": { "version": "250231.0.0", - "license": "BSD-2-Clause", - "peer": true + "license": "BSD-2-Clause" }, "node_modules/jsc-safe-url": { "version": "0.2.4", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/jscodeshift": { "version": "0.14.0", "license": "MIT", - "peer": true, "dependencies": { "@babel/core": "^7.13.16", "@babel/parser": "^7.13.16", @@ -22302,7 +23018,6 @@ "node_modules/jscodeshift/node_modules/ansi-styles": { "version": "4.3.0", "license": "MIT", - "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -22316,7 +23031,6 @@ "node_modules/jscodeshift/node_modules/chalk": { "version": "4.1.2", "license": "MIT", - "peer": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -22331,7 +23045,6 @@ "node_modules/jscodeshift/node_modules/color-convert": { "version": "2.0.1", "license": "MIT", - "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -22341,13 +23054,11 @@ }, "node_modules/jscodeshift/node_modules/color-name": { "version": "1.1.4", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/jscodeshift/node_modules/has-flag": { "version": "4.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">=8" } @@ -22355,7 +23066,6 @@ "node_modules/jscodeshift/node_modules/supports-color": { "version": "7.2.0", "license": "MIT", - "peer": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -23388,7 +24098,6 @@ "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", "license": "Apache-2.0", - "peer": true, "dependencies": { "debug": "^2.6.9", "marky": "^1.2.2" @@ -23399,7 +24108,6 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } @@ -23408,8 +24116,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lightningcss": { "version": "1.27.0", @@ -23783,8 +24490,7 @@ }, "node_modules/lodash.throttle": { "version": "4.1.1", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/lodash.uniq": { "version": "4.5.0", @@ -24049,8 +24755,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", - "license": "Apache-2.0", - "peer": true + "license": "Apache-2.0" }, "node_modules/math-intrinsics": { "version": "1.1.0", @@ -24073,8 +24778,7 @@ }, "node_modules/memoize-one": { "version": "5.2.1", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/meow": { "version": "8.1.2", @@ -25333,7 +26037,6 @@ "node_modules/mkdirp": { "version": "0.5.6", "license": "MIT", - "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -25489,7 +26192,6 @@ "node_modules/negotiator": { "version": "0.6.3", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -25521,7 +26223,6 @@ "node_modules/node-dir": { "version": "0.1.17", "license": "MIT", - "peer": true, "dependencies": { "minimatch": "^3.0.2" }, @@ -25534,7 +26235,6 @@ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "license": "MIT", - "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -25543,7 +26243,6 @@ "node_modules/node-dir/node_modules/minimatch": { "version": "3.1.2", "license": "ISC", - "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -25594,7 +26293,6 @@ "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "license": "(BSD-3-Clause OR GPL-2.0)", - "peer": true, "engines": { "node": ">= 6.13.0" } @@ -26377,8 +27075,7 @@ }, "node_modules/nullthrows": { "version": "1.1.1", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/nwsapi": { "version": "2.2.13", @@ -26832,7 +27529,6 @@ "node_modules/on-finished": { "version": "2.3.0", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -26875,7 +27571,6 @@ "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "license": "MIT", - "peer": true, "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" @@ -27628,7 +28323,6 @@ "node_modules/parseurl": { "version": "1.3.3", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -28758,6 +29452,15 @@ "node": ">=0.4.0" } }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "dependencies": { + "asap": "~2.0.6" + } + }, "node_modules/promise-all-reject-late": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", @@ -29041,7 +29744,6 @@ "node_modules/queue": { "version": "6.0.2", "license": "MIT", - "peer": true, "dependencies": { "inherits": "~2.0.3" } @@ -29092,7 +29794,6 @@ "node_modules/range-parser": { "version": "1.2.1", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -29263,6 +29964,80 @@ "react-native": ">=0.56" } }, + "node_modules/react-native-svg": { + "version": "15.15.1", + "resolved": "https://registry.npmjs.org/react-native-svg/-/react-native-svg-15.15.1.tgz", + "integrity": "sha512-ZUD1xwc3Hwo4cOmOLumjJVoc7lEf9oQFlHnLmgccLC19fNm6LVEdtB+Cnip6gEi0PG3wfvVzskViEtrySQP8Fw==", + "license": "MIT", + "dependencies": { + "css-select": "^5.1.0", + "css-tree": "^1.1.3", + "warn-once": "0.1.1" + }, + "peerDependencies": { + "react": "*", + "react-native": "*" + } + }, + "node_modules/react-native-svg/node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/react-native-svg/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/react-native-svg/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/react-native-svg/node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/react-native-url-polyfill": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/react-native-url-polyfill/-/react-native-url-polyfill-2.0.0.tgz", @@ -29388,14 +30163,6 @@ "node": ">= 10" } }, - "node_modules/react-native/node_modules/promise": { - "version": "8.3.0", - "license": "MIT", - "peer": true, - "dependencies": { - "asap": "~2.0.6" - } - }, "node_modules/react-native/node_modules/react-is": { "version": "17.0.2", "license": "MIT", @@ -29438,7 +30205,6 @@ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -29501,7 +30267,6 @@ "node_modules/react-shallow-renderer": { "version": "16.15.0", "license": "MIT", - "peer": true, "dependencies": { "object-assign": "^4.1.1", "react-is": "^16.12.0 || ^17.0.0 || ^18.0.0" @@ -29855,8 +30620,7 @@ }, "node_modules/readline": { "version": "1.3.0", - "license": "BSD", - "peer": true + "license": "BSD" }, "node_modules/real-require": { "version": "0.1.0", @@ -29868,7 +30632,6 @@ "node_modules/recast": { "version": "0.21.5", "license": "MIT", - "peer": true, "dependencies": { "ast-types": "0.15.2", "esprima": "~4.0.0", @@ -29881,8 +30644,7 @@ }, "node_modules/recast/node_modules/tslib": { "version": "2.8.1", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/rechoir": { "version": "0.8.0", @@ -30533,7 +31295,6 @@ "node_modules/scheduler": { "version": "0.24.0-canary-efb381bbf-20230505", "license": "MIT", - "peer": true, "dependencies": { "loose-envify": "^1.1.0" } @@ -30555,6 +31316,20 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/semver": { "version": "6.3.1", "license": "ISC", @@ -30653,7 +31428,6 @@ "node_modules/serialize-error": { "version": "2.1.0", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -30668,7 +31442,6 @@ "node_modules/serve-static": { "version": "1.16.2", "license": "MIT", - "peer": true, "dependencies": { "encodeurl": "~2.0.0", "escape-html": "~1.0.3", @@ -30682,20 +31455,17 @@ "node_modules/serve-static/node_modules/debug": { "version": "2.6.9", "license": "MIT", - "peer": true, "dependencies": { "ms": "2.0.0" } }, "node_modules/serve-static/node_modules/debug/node_modules/ms": { "version": "2.0.0", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/serve-static/node_modules/encodeurl": { "version": "2.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -30703,7 +31473,6 @@ "node_modules/serve-static/node_modules/mime": { "version": "1.6.0", "license": "MIT", - "peer": true, "bin": { "mime": "cli.js" }, @@ -30714,7 +31483,6 @@ "node_modules/serve-static/node_modules/on-finished": { "version": "2.4.1", "license": "MIT", - "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -30725,7 +31493,6 @@ "node_modules/serve-static/node_modules/send": { "version": "0.19.0", "license": "MIT", - "peer": true, "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -30748,7 +31515,6 @@ "node_modules/serve-static/node_modules/send/node_modules/encodeurl": { "version": "1.0.2", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -30756,7 +31522,6 @@ "node_modules/serve-static/node_modules/statuses": { "version": "2.0.1", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -30784,8 +31549,7 @@ }, "node_modules/setprototypeof": { "version": "1.2.0", - "license": "ISC", - "peer": true + "license": "ISC" }, "node_modules/sha.js": { "version": "2.4.12", @@ -31216,13 +31980,11 @@ }, "node_modules/stackframe": { "version": "1.3.4", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/stacktrace-parser": { "version": "0.1.10", "license": "MIT", - "peer": true, "dependencies": { "type-fest": "^0.7.1" }, @@ -31233,7 +31995,6 @@ "node_modules/stacktrace-parser/node_modules/type-fest": { "version": "0.7.1", "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=8" } @@ -31241,7 +32002,6 @@ "node_modules/statuses": { "version": "1.5.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.6" } @@ -31785,7 +32545,6 @@ "node_modules/temp": { "version": "0.8.4", "license": "MIT", - "peer": true, "dependencies": { "rimraf": "~2.6.2" }, @@ -31806,7 +32565,6 @@ "node_modules/temp/node_modules/rimraf": { "version": "2.6.3", "license": "ISC", - "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -32010,8 +32768,7 @@ }, "node_modules/throat": { "version": "5.0.0", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/through": { "version": "2.3.8", @@ -32132,7 +32889,6 @@ "node_modules/toidentifier": { "version": "1.0.1", "license": "MIT", - "peer": true, "engines": { "node": ">=0.6" } @@ -32844,7 +33600,6 @@ "node_modules/unpipe": { "version": "1.0.0", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.8" } @@ -33112,7 +33867,6 @@ "node_modules/utils-merge": { "version": "1.0.1", "license": "MIT", - "peer": true, "engines": { "node": ">= 0.4.0" } @@ -33369,8 +34123,7 @@ }, "node_modules/vlq": { "version": "1.0.1", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/w3c-xmlserializer": { "version": "4.0.0", @@ -33441,6 +34194,12 @@ "makeerror": "1.0.12" } }, + "node_modules/warn-once": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/warn-once/-/warn-once-0.1.1.tgz", + "integrity": "sha512-VkQZJbO8zVImzYFteBXvBOZEl1qL175WH8VmZcxF2fZAoudNhNDvHi+doCaAEdU2l2vtcIwa2zn0QK5+I1HQ3Q==", + "license": "MIT" + }, "node_modules/watchpack": { "version": "2.4.2", "dev": true, @@ -33628,8 +34387,7 @@ }, "node_modules/whatwg-fetch": { "version": "3.6.20", - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/whatwg-mimetype": { "version": "3.0.0", @@ -34137,7 +34895,7 @@ }, "packages/config": { "name": "@onflow/config", - "version": "1.10.0", + "version": "1.11.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -34172,7 +34930,7 @@ }, "packages/demo": { "name": "@onflow/demo", - "version": "1.7.0", + "version": "1.8.1", "dependencies": { "@onflow/fcl": "file:../fcl", "@onflow/react-sdk": "file:../react-sdk", @@ -34605,16 +35363,16 @@ }, "packages/fcl": { "name": "@onflow/fcl", - "version": "1.21.7", + "version": "1.21.9", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", - "@onflow/config": "1.10.0", - "@onflow/fcl-core": "1.29.0", - "@onflow/fcl-wc": "6.0.19", + "@onflow/config": "1.11.1", + "@onflow/fcl-core": "1.30.1", + "@onflow/fcl-wc": "6.0.21", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.4", - "@onflow/sdk": "1.13.5", + "@onflow/sdk": "1.13.7", "@onflow/types": "1.5.0", "@onflow/util-actor": "1.3.5", "@onflow/util-address": "1.2.4", @@ -34680,16 +35438,16 @@ }, "packages/fcl-core": { "name": "@onflow/fcl-core", - "version": "1.29.0", + "version": "1.30.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@improbable-eng/grpc-web": "^0.15.0", - "@onflow/config": "1.10.0", + "@onflow/config": "1.11.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.4", - "@onflow/sdk": "1.13.5", - "@onflow/transport-http": "1.15.4", + "@onflow/sdk": "1.13.7", + "@onflow/transport-http": "1.15.6", "@onflow/types": "1.5.0", "@onflow/util-actor": "1.3.5", "@onflow/util-address": "1.2.4", @@ -34749,14 +35507,14 @@ }, "packages/fcl-ethereum-provider": { "name": "@onflow/fcl-ethereum-provider", - "version": "0.0.21", + "version": "0.1.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", "@noble/hashes": "^1.7.1", - "@onflow/fcl-wc": "6.0.19", + "@onflow/fcl-wc": "6.0.21", "@onflow/rlp": "^1.2.4", "@walletconnect/ethereum-provider": "^2.20.2", "@walletconnect/jsonrpc-http-connection": "^1.0.8", @@ -34777,7 +35535,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.21.7" + "@onflow/fcl": "1.21.9" } }, "packages/fcl-ethereum-provider/node_modules/@scure/bip32": { @@ -35005,14 +35763,14 @@ }, "packages/fcl-rainbowkit-adapter": { "name": "@onflow/fcl-rainbowkit-adapter", - "version": "0.2.17", + "version": "0.3.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.21", - "@onflow/fcl-wagmi-adapter": "0.0.21", + "@onflow/fcl-ethereum-provider": "0.1.1", + "@onflow/fcl-wagmi-adapter": "0.1.1", "@onflow/rlp": "^1.2.4", "@wagmi/core": "^2.16.3", "mipd": "^0.0.7", @@ -35033,7 +35791,7 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.21.7", + "@onflow/fcl": "1.21.9", "@rainbow-me/rainbowkit": "^2.2.3", "react": "17.x || 18.x || 19.x" } @@ -35050,15 +35808,15 @@ }, "packages/fcl-react-native": { "name": "@onflow/fcl-react-native", - "version": "1.19.0", + "version": "1.20.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", - "@onflow/config": "1.10.0", - "@onflow/fcl-core": "1.29.0", + "@onflow/config": "1.11.1", + "@onflow/fcl-core": "1.30.1", "@onflow/interaction": "0.0.11", "@onflow/rlp": "1.2.4", - "@onflow/sdk": "1.13.5", + "@onflow/sdk": "1.13.7", "@onflow/types": "1.5.0", "@onflow/util-actor": "1.3.5", "@onflow/util-address": "1.2.4", @@ -35497,13 +36255,13 @@ }, "packages/fcl-wagmi-adapter": { "name": "@onflow/fcl-wagmi-adapter", - "version": "0.0.21", + "version": "0.1.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@ethersproject/bytes": "^5.7.0", "@ethersproject/hash": "^5.7.0", - "@onflow/fcl-ethereum-provider": "0.0.21", + "@onflow/fcl-ethereum-provider": "0.1.1", "@onflow/rlp": "^1.2.4", "viem": "^2.22.21" }, @@ -35519,17 +36277,17 @@ "jest": "^29.7.0" }, "peerDependencies": { - "@onflow/fcl": "1.21.7", + "@onflow/fcl": "1.21.9", "@wagmi/core": "^2.16.3" } }, "packages/fcl-wc": { "name": "@onflow/fcl-wc", - "version": "6.0.19", + "version": "6.0.21", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", - "@onflow/config": "1.10.0", + "@onflow/config": "1.11.1", "@onflow/util-invariant": "1.2.5", "@onflow/util-logger": "1.3.4", "@walletconnect/modal": "^2.7.0", @@ -35552,7 +36310,7 @@ "jest-preset-preact": "^4.1.1" }, "peerDependencies": { - "@onflow/fcl-core": "1.29.0" + "@onflow/fcl-core": "1.30.1" } }, "packages/fcl-wc/node_modules/@scure/bip32": { @@ -35829,11 +36587,11 @@ }, "packages/react-core": { "name": "@onflow/react-core", - "version": "0.7.0", + "version": "0.8.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", - "@onflow/fcl-core": "^1.29.0", + "@onflow/fcl-core": "^1.30.1", "@onflow/typedefs": "^1.8.0", "@tanstack/react-query": "^5.67.3" }, @@ -35871,14 +36629,547 @@ "node": ">=4.2.0" } }, + "packages/react-native-sdk": { + "name": "@onflow/react-native-sdk", + "version": "0.1.0", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.25.7", + "@onflow/react-core": "0.8.1", + "@tanstack/react-query": "^5.67.3", + "expo-clipboard": "^7.0.0", + "react-native-svg": "^15.8.0" + }, + "devDependencies": { + "@babel/preset-env": "^7.26.9", + "@babel/preset-react": "^7.26.3", + "@babel/preset-typescript": "^7.25.7", + "@onflow/fcl-bundle": "1.7.1", + "@onflow/typedefs": "^1.8.0", + "@tanstack/react-query": "^5.67.3", + "@testing-library/react-native": "^12.4.3", + "@types/jest": "^29.5.13", + "@types/react": "^18.2.6", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "eslint": "^8.57.1", + "jest": "^29.7.0", + "react": "^18.3.1", + "react-native": "^0.76.0", + "react-test-renderer": "^18.3.1", + "typescript": "^5.9.2", + "viem": "^2.29.2" + }, + "peerDependencies": { + "@onflow/fcl-react-native": ">=1.20.1", + "react": "^18.0.0 || ^19.0.0", + "react-native": ">=0.70.0", + "viem": "^2.29.2" + } + }, + "packages/react-native-sdk/node_modules/@react-native/assets-registry": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.76.9.tgz", + "integrity": "sha512-pN0Ws5xsjWOZ8P37efh0jqHHQmq+oNGKT4AyAoKRpxBDDDmlAmpaYjer9Qz7PpDKF+IUyRjF/+rBsM50a8JcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "packages/react-native-sdk/node_modules/@react-native/codegen": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.76.9.tgz", + "integrity": "sha512-AzlCHMTKrAVC2709V4ZGtBXmGVtWTpWm3Ruv5vXcd3/anH4mGucfJ4rjbWKdaYQJMpXa3ytGomQrsIsT/s8kgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.25.3", + "glob": "^7.1.1", + "hermes-parser": "0.23.1", + "invariant": "^2.2.4", + "jscodeshift": "^0.14.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1", + "yargs": "^17.6.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@babel/preset-env": "^7.1.6" + } + }, + "packages/react-native-sdk/node_modules/@react-native/gradle-plugin": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.76.9.tgz", + "integrity": "sha512-uGzp3dL4GfNDz+jOb8Nik1Vrfq1LHm0zESizrGhHACFiFlUSflVAnWuUAjlZlz5XfLhzGVvunG4Vdrpw8CD2ng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "packages/react-native-sdk/node_modules/@react-native/js-polyfills": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.76.9.tgz", + "integrity": "sha512-s6z6m8cK4SMjIX1hm8LT187aQ6//ujLrjzDBogqDCYXRbfjbAYovw5as/v2a2rhUIyJbS3UjokZm3W0H+Oh/RQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "packages/react-native-sdk/node_modules/@react-native/normalize-colors": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.76.9.tgz", + "integrity": "sha512-TUdMG2JGk72M9d8DYbubdOlrzTYjw+YMe/xOnLU4viDgWRHsCbtRS9x0IAxRjs3amj/7zmK3Atm8jUPvdAc8qw==", + "dev": true, + "license": "MIT" + }, + "packages/react-native-sdk/node_modules/@react-native/virtualized-lists": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.76.9.tgz", + "integrity": "sha512-2neUfZKuqMK2LzfS8NyOWOyWUJOWgDym5fUph6fN9qF+LNPjAvnc4Zr9+o+59qjNu/yXwQgVMWNU4+8WJuPVWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^18.2.6", + "react": "*", + "react-native": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "packages/react-native-sdk/node_modules/@testing-library/react-native": { + "version": "12.9.0", + "resolved": "https://registry.npmjs.org/@testing-library/react-native/-/react-native-12.9.0.tgz", + "integrity": "sha512-wIn/lB1FjV2N4Q7i9PWVRck3Ehwq5pkhAef5X5/bmQ78J/NoOsGbVY2/DG5Y9Lxw+RfE+GvSEh/fe5Tz6sKSvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "jest-matcher-utils": "^29.7.0", + "pretty-format": "^29.7.0", + "redent": "^3.0.0" + }, + "peerDependencies": { + "jest": ">=28.0.0", + "react": ">=16.8.0", + "react-native": ">=0.59", + "react-test-renderer": ">=16.8.0" + }, + "peerDependenciesMeta": { + "jest": { + "optional": true + } + } + }, + "packages/react-native-sdk/node_modules/@types/react": { + "version": "18.3.27", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.27.tgz", + "integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.2.2" + } + }, + "packages/react-native-sdk/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "packages/react-native-sdk/node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.23.1.tgz", + "integrity": "sha512-uNLD0tk2tLUjGFdmCk+u/3FEw2o+BAwW4g+z2QVlxJrzZYOOPADroEcNtTPt5lNiScctaUmnsTkVEnOwZUOLhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-parser": "0.23.1" + } + }, + "packages/react-native-sdk/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "packages/react-native-sdk/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "packages/react-native-sdk/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "packages/react-native-sdk/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "packages/react-native-sdk/node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "dev": true, + "license": "MIT" + }, + "packages/react-native-sdk/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "packages/react-native-sdk/node_modules/hermes-estree": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.23.1.tgz", + "integrity": "sha512-eT5MU3f5aVhTqsfIReZ6n41X5sYn4IdQL0nvz6yO+MMlPxw49aSARHLg/MSehQftyjnrE8X6bYregzSumqc6cg==", + "dev": true, + "license": "MIT" + }, + "packages/react-native-sdk/node_modules/hermes-parser": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.23.1.tgz", + "integrity": "sha512-oxl5h2DkFW83hT4DAUJorpah8ou4yvmweUzLJmmr6YV2cezduCdlil1AvU/a/xSsAFo4WUcNA4GoV5Bvq6JffA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hermes-estree": "0.23.1" + } + }, + "packages/react-native-sdk/node_modules/metro-runtime": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.81.5.tgz", + "integrity": "sha512-M/Gf71ictUKP9+77dV/y8XlAWg7xl76uhU7ggYFUwEdOHHWPG6gLBr1iiK0BmTjPFH8yRo/xyqMli4s3oGorPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "packages/react-native-sdk/node_modules/metro-source-map": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.81.5.tgz", + "integrity": "sha512-Jz+CjvCKLNbJZYJTBeN3Kq9kIJf6b61MoLBdaOQZJ5Ajhw6Pf95Nn21XwA8BwfUYgajsi6IXsp/dTZsYJbN00Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.25.3", + "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3", + "@babel/types": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.81.5", + "nullthrows": "^1.1.1", + "ob1": "0.81.5", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": ">=18.18" + } + }, + "packages/react-native-sdk/node_modules/metro-symbolicate": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.81.5.tgz", + "integrity": "sha512-X3HV3n3D6FuTE11UWFICqHbFMdTavfO48nXsSpnNGFkUZBexffu0Xd+fYKp+DJLNaQr3S+lAs8q9CgtDTlRRuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.81.5", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": ">=18.18" + } + }, + "packages/react-native-sdk/node_modules/ob1": { + "version": "0.81.5", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.81.5.tgz", + "integrity": "sha512-iNpbeXPLmaiT9I5g16gFFFjsF3sGxLpYG2EGP3dfFB4z+l9X60mp/yRzStHhMtuNt8qmf7Ww80nOPQHngHhnIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": ">=18.18" + } + }, + "packages/react-native-sdk/node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "packages/react-native-sdk/node_modules/react-devtools-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-5.3.2.tgz", + "integrity": "sha512-crr9HkVrDiJ0A4zot89oS0Cgv0Oa4OG1Em4jit3P3ZxZSKPMYyMjfwMqgcJna9o625g8oN87rBm8SWWrSTBZxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, + "packages/react-native-sdk/node_modules/react-devtools-core/node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "packages/react-native-sdk/node_modules/react-native": { + "version": "0.76.9", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.76.9.tgz", + "integrity": "sha512-+LRwecWmTDco7OweGsrECIqJu0iyrREd6CTCgC/uLLYipiHvk+MH9nd6drFtCw/6Blz6eoKTcH9YTTJusNtrWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/create-cache-key-function": "^29.6.3", + "@react-native/assets-registry": "0.76.9", + "@react-native/codegen": "0.76.9", + "@react-native/community-cli-plugin": "0.76.9", + "@react-native/gradle-plugin": "0.76.9", + "@react-native/js-polyfills": "0.76.9", + "@react-native/normalize-colors": "0.76.9", + "@react-native/virtualized-lists": "0.76.9", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-jest": "^29.7.0", + "babel-plugin-syntax-hermes-parser": "^0.23.1", + "base64-js": "^1.5.1", + "chalk": "^4.0.0", + "commander": "^12.0.0", + "event-target-shim": "^5.0.1", + "flow-enums-runtime": "^0.0.6", + "glob": "^7.1.1", + "invariant": "^2.2.4", + "jest-environment-node": "^29.6.3", + "jsc-android": "^250231.0.0", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.81.0", + "metro-source-map": "^0.81.0", + "mkdirp": "^0.5.1", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^5.3.1", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.24.0-canary-efb381bbf-20230505", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "whatwg-fetch": "^3.0.0", + "ws": "^6.2.3", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/react": "^18.2.6", + "react": "^18.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "packages/react-native-sdk/node_modules/react-test-renderer": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-test-renderer/-/react-test-renderer-18.3.1.tgz", + "integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "react-is": "^18.3.1", + "react-shallow-renderer": "^16.15.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "packages/react-native-sdk/node_modules/react-test-renderer/node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "packages/react-native-sdk/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "dev": true, + "license": "MIT" + }, + "packages/react-native-sdk/node_modules/semver": { + "version": "7.7.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.3.tgz", + "integrity": "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "packages/react-native-sdk/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "packages/react-native-sdk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "packages/react-native-sdk/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "packages/react-native-sdk/node_modules/ws": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.3.tgz", + "integrity": "sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-limiter": "~1.0.0" + } + }, "packages/react-sdk": { "name": "@onflow/react-sdk", - "version": "0.17.0", + "version": "0.18.1", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", "@headlessui/react": "^2.2.2", - "@onflow/react-core": "0.7.0", + "@onflow/react-core": "0.8.1", "@tanstack/react-query": "^5.67.3", "@testing-library/react": "^16.2.0", "tailwind-merge": "^3.3.1" @@ -35904,7 +37195,7 @@ "tailwindcss": "^3.4.14" }, "peerDependencies": { - "@onflow/fcl": ">=1.21.7", + "@onflow/fcl": ">=1.21.9", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "viem": "^2.29.2" @@ -35931,13 +37222,13 @@ }, "packages/sdk": { "name": "@onflow/sdk", - "version": "1.13.5", + "version": "1.13.7", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", - "@onflow/config": "1.10.0", + "@onflow/config": "1.11.1", "@onflow/rlp": "1.2.4", - "@onflow/transport-http": "1.15.4", + "@onflow/transport-http": "1.15.6", "@onflow/typedefs": "1.8.0", "@onflow/types": "1.5.0", "@onflow/util-actor": "1.3.5", @@ -35987,13 +37278,13 @@ }, "devDependencies": { "@onflow/fcl-bundle": "1.7.1", - "@onflow/sdk": "1.13.5", + "@onflow/sdk": "1.13.7", "jest": "^29.7.0" } }, "packages/transport-http": { "name": "@onflow/transport-http", - "version": "1.15.4", + "version": "1.15.6", "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.25.7", @@ -36011,7 +37302,7 @@ "devDependencies": { "@onflow/fcl-bundle": "1.7.1", "@onflow/rlp": "1.2.4", - "@onflow/sdk": "1.13.5", + "@onflow/sdk": "1.13.7", "@onflow/types": "1.5.0", "jest": "^29.7.0", "jest-websocket-mock": "^2.5.0", diff --git a/packages/demo/src/components/starter-banner.tsx b/packages/demo/src/components/starter-banner.tsx index fbc83ae55..bdda1a574 100644 --- a/packages/demo/src/components/starter-banner.tsx +++ b/packages/demo/src/components/starter-banner.tsx @@ -30,46 +30,91 @@ export function StarterBanner() { -
-
-
-

- Looking for a starter? -

-

- Try our Next.js starter template with Flow React SDK - pre-configured and ready to be used. -

+
+
+
+
+

+ Looking for a starter? +

+

+ Try our Next.js starter template with Flow React SDK + pre-configured and ready to be used. +

+
+ + + View Starter + + + +
+
+ +
+
+
+

+ Building for mobile? +

+

+ Try our Expo starter template with Flow React Native SDK + pre-configured and ready to be used. +

+
- - View Starter - - - - + View Starter + + + + +
diff --git a/packages/fcl-react-native/src/client.ts b/packages/fcl-react-native/src/client.ts index 6bb9382ad..f56d692ce 100644 --- a/packages/fcl-react-native/src/client.ts +++ b/packages/fcl-react-native/src/client.ts @@ -6,6 +6,7 @@ import { import {getAsyncStorage} from "./utils/react-native/storage" import {loadFclWc} from "./walletconnect/loader" import {DISCOVERY_RN_METHOD} from "./utils/react-native/constants" +import {disconnectWalletConnect} from "./walletconnect/client" const PLATFORM = "react-native" @@ -31,9 +32,9 @@ export interface FlowClientConfig * Creates a Flow client instance with authentication, transaction, and query capabilities for React Native. * * @param params Configuration object for the Flow client - * @returns A promise that resolves to a Flow client object with many methods for interacting with the Flow blockchain + * @returns A Flow client object with many methods for interacting with the Flow blockchain */ -export async function createFlowClient(params: FlowClientConfig) { +export function createFlowClient(params: FlowClientConfig) { // TODO: Load into the global plugin registry for now. This should be // refactored to use a plugin registry bound to the client instance in the future. // Auto-load WalletConnect plugin when projectId is provided @@ -71,7 +72,14 @@ export async function createFlowClient(params: FlowClientConfig) { serviceOpenIdScopes: params.serviceOpenIdScopes, }) + // Create unauthenticate that also disconnects WalletConnect sessions + const unauthenticate = async () => { + fclCore.unauthenticate() + await disconnectWalletConnect() + } + return { ...fclCore, + unauthenticate, } } diff --git a/packages/fcl-react-native/src/fcl-react-native.ts b/packages/fcl-react-native/src/fcl-react-native.ts index 551973ebb..cca5dc058 100644 --- a/packages/fcl-react-native/src/fcl-react-native.ts +++ b/packages/fcl-react-native/src/fcl-react-native.ts @@ -1,3 +1,7 @@ +// Polyfill must be imported first +// This provides crypto.getRandomValues for WalletConnect +import "react-native-get-random-values" + export { VERSION, query, @@ -76,7 +80,7 @@ import { setIsReactNative, } from "@onflow/fcl-core" -import {getClient} from "./walletconnect/client" +import {disconnectWalletConnect} from "./walletconnect/client" // Get AsyncStorage instance when module loads // This ensures storage is ready before any component subscribes to currentUser @@ -93,32 +97,8 @@ export const mutate = getMutate(currentUser) export const authenticate = (opts = {}) => currentUser().authenticate(opts) export const unauthenticate = async () => { - // First unauthenticate from FCL currentUser().unauthenticate() - - // Then disconnect WalletConnect (both sessions and pairings for complete cleanup) - try { - const client = await getClient() - if (!client) return - - const sessions = client.session.getAll() - const pairings = client.core.pairing.pairings.getAll() - - // Disconnect all in parallel - await Promise.allSettled([ - ...sessions.map((session: any) => - client.disconnect({ - topic: session.topic, - reason: {code: 6000, message: "User disconnected"}, - }) - ), - ...pairings.map((pairing: any) => - client.core.pairing.disconnect({topic: pairing.topic}) - ), - ]) - } catch { - // WC client not initialized or disconnect failed (safe to ignore) - } + await disconnectWalletConnect() } export const reauthenticate = async (opts = {}) => { diff --git a/packages/fcl-react-native/src/walletconnect/client.ts b/packages/fcl-react-native/src/walletconnect/client.ts index 60571ad75..1acbd6f2b 100644 --- a/packages/fcl-react-native/src/walletconnect/client.ts +++ b/packages/fcl-react-native/src/walletconnect/client.ts @@ -151,3 +151,28 @@ export async function getClient() { return client }) } + +export async function disconnectWalletConnect(): Promise { + try { + const client = await getClient() + if (!client) return + + const sessions = client.session.getAll() + const pairings = client.core.pairing.pairings.getAll() + + // Disconnect all in parallel + await Promise.allSettled([ + ...sessions.map((session: any) => + client.disconnect({ + topic: session.topic, + reason: {code: 6000, message: "User disconnected"}, + }) + ), + ...pairings.map((pairing: any) => + client.core.pairing.disconnect({topic: pairing.topic}) + ), + ]) + } catch { + // WC client not initialized or disconnect failed (safe to ignore) + } +} diff --git a/packages/fcl-react-native/src/walletconnect/service.ts b/packages/fcl-react-native/src/walletconnect/service.ts index df187f515..5abb1c249 100644 --- a/packages/fcl-react-native/src/walletconnect/service.ts +++ b/packages/fcl-react-native/src/walletconnect/service.ts @@ -92,11 +92,18 @@ function determineWalletAppLink( service: any, storedWalletAppLink: string | null ): string { - if (method === FLOW_METHODS.FLOW_AUTHN) { - // For initial authn request, use service.uid - return service.uid + const uid = + method === FLOW_METHODS.FLOW_AUTHN + ? service.uid + : storedWalletAppLink || service.uid + + // Transform uid format (e.g., "frw#authz") to deeplink URL (e.g., "frw://authz") + // Service UIDs use # as separator but mobile deeplinks need :// + if (uid && uid.includes("#") && !uid.includes("://")) { + return uid.replace("#", "://") } - return storedWalletAppLink || service.uid + + return uid } function injectSessionIntoPreAuthz( diff --git a/packages/react-core/src/provider/FlowQueryClient.ts b/packages/react-core/src/provider/FlowQueryClient.tsx similarity index 57% rename from packages/react-core/src/provider/FlowQueryClient.ts rename to packages/react-core/src/provider/FlowQueryClient.tsx index 7059a9ade..34905a340 100644 --- a/packages/react-core/src/provider/FlowQueryClient.ts +++ b/packages/react-core/src/provider/FlowQueryClient.tsx @@ -1,4 +1,4 @@ -import {createContext, useContext} from "react" +import React, {createContext, useContext, PropsWithChildren} from "react" import {QueryClient} from "@tanstack/react-query" export const FlowQueryClientContext = createContext( @@ -14,3 +14,12 @@ export function useFlowQueryClient() { } return queryClient } + +export function FlowQueryClientProvider({ + queryClient, + children, +}: PropsWithChildren<{queryClient: QueryClient}>) { + return ( + + ) +} diff --git a/packages/react-sdk/src/provider/GlobalTransactionProvider.tsx b/packages/react-core/src/provider/GlobalTransactionProvider.tsx similarity index 51% rename from packages/react-sdk/src/provider/GlobalTransactionProvider.tsx rename to packages/react-core/src/provider/GlobalTransactionProvider.tsx index 9ebde4557..3de711146 100644 --- a/packages/react-sdk/src/provider/GlobalTransactionProvider.tsx +++ b/packages/react-core/src/provider/GlobalTransactionProvider.tsx @@ -1,23 +1,39 @@ -import {TransactionExecutionStatus} from "@onflow/typedefs" import React, {createContext, useContext, useState, useEffect} from "react" -import {useFlowClient} from "@onflow/react-core" +import {TransactionExecutionStatus} from "@onflow/typedefs" +import {useFlowClient} from "../hooks/useFlowClient" interface GlobalTransactionContextValue { - /** Check if a global transaction is currently running */ + /** Current global transaction ID, or null if none */ globalTxId: string | null - /** Set the global transaction running state */ + /** Set the global transaction ID */ setGlobalTxId: (txId: string | null) => void } const GlobalTransactionContext = createContext(null) -export const useGlobalTransaction = (): GlobalTransactionContextValue => { +/** + * Hook to access and manage the global transaction state. + * + * @throws Error if used outside of FlowProvider + * + * @example + * ```tsx + * const {globalTxId, setGlobalTxId} = useGlobalTransaction() + * + * // Start tracking a transaction + * setGlobalTxId(txId) + * + * // Check if a transaction is in progress + * if (globalTxId) { + * console.log("Transaction in progress:", globalTxId) + * } + * ``` + */ +export function useGlobalTransaction(): GlobalTransactionContextValue { const context = useContext(GlobalTransactionContext) if (!context) { - throw new Error( - "useGlobalTransaction must be used within a GlobalTransactionProvider" - ) + throw new Error("useGlobalTransaction must be used within a FlowProvider") } return context } @@ -26,27 +42,27 @@ interface GlobalTransactionProviderProps { children: React.ReactNode } -export const GlobalTransactionProvider: React.FC< - GlobalTransactionProviderProps -> = ({children}) => { +/** + * Provider that tracks a single global transaction. + * Automatically clears the transaction ID when the transaction is executed. + */ +export function GlobalTransactionProvider({ + children, +}: GlobalTransactionProviderProps) { const [txId, setTxId] = useState(null) const fcl = useFlowClient() useEffect(() => { if (!txId) return - // Subscribe to transaction updates const unsub = fcl.tx(txId).subscribe( - txStatus => { + (txStatus: {status: number}) => { if (txStatus.status >= TransactionExecutionStatus.EXECUTED) { - // Transaction has been executed, reset the global transaction ID setTxId(null) } }, - error => { - // Handle subscription errors + (error: Error) => { console.error("Transaction status subscription error:", error) - // Clear the transaction ID to prevent button from staying in processing state setTxId(null) } ) @@ -56,7 +72,7 @@ export const GlobalTransactionProvider: React.FC< } }, [txId]) - const globalTransactionValue: GlobalTransactionContextValue = { + const value: GlobalTransactionContextValue = { globalTxId: txId, setGlobalTxId: (newTxId: string | null) => { if (newTxId !== txId) { @@ -66,7 +82,7 @@ export const GlobalTransactionProvider: React.FC< } return ( - + {children} ) diff --git a/packages/react-core/src/provider/index.ts b/packages/react-core/src/provider/index.ts index 8416d7434..0dabce0a4 100644 --- a/packages/react-core/src/provider/index.ts +++ b/packages/react-core/src/provider/index.ts @@ -1 +1,9 @@ -export {useFlowQueryClient, FlowQueryClientContext} from "./FlowQueryClient" +export { + useFlowQueryClient, + FlowQueryClientContext, + FlowQueryClientProvider, +} from "./FlowQueryClient" +export { + useGlobalTransaction, + GlobalTransactionProvider, +} from "./GlobalTransactionProvider" diff --git a/packages/react-core/src/utils/address.ts b/packages/react-core/src/utils/address.ts new file mode 100644 index 000000000..7c72af36c --- /dev/null +++ b/packages/react-core/src/utils/address.ts @@ -0,0 +1,4 @@ +export const truncateAddress = (address: string): string => { + if (!address) return "" + return `${address.slice(0, 6)}...${address.slice(-4)}` +} diff --git a/packages/react-core/src/utils/index.ts b/packages/react-core/src/utils/index.ts index b5a7897ed..d6066eac3 100644 --- a/packages/react-core/src/utils/index.ts +++ b/packages/react-core/src/utils/index.ts @@ -1,2 +1,3 @@ +export * from "./address" export * from "./deepEqual" export * from "./flowscan" diff --git a/packages/react-native-sdk/.babelrc b/packages/react-native-sdk/.babelrc new file mode 100644 index 000000000..f723d8bb9 --- /dev/null +++ b/packages/react-native-sdk/.babelrc @@ -0,0 +1,7 @@ +{ + "presets": [ + "@babel/preset-typescript", + "@babel/preset-env", + ["@babel/preset-react", {"runtime": "automatic"}] + ] +} diff --git a/packages/react-native-sdk/README.md b/packages/react-native-sdk/README.md new file mode 100644 index 000000000..77c3397a8 --- /dev/null +++ b/packages/react-native-sdk/README.md @@ -0,0 +1,63 @@ +# @onflow/react-native-sdk + +A React Native library that provides hooks for interacting with the Flow blockchain. It helps you authenticate users, run Cadence scripts and transactions, listen to events, and manage network configuration directly from your components. Fully compatible with Expo. + +This package provides a comparable API to [@onflow/react-sdk](https://www.npmjs.com/package/@onflow/react-sdk) for React Native applications. See the hooks in action in the [React SDK Playground](https://react.flow.com). + +## 🔧 Installation + +```bash +npm install @onflow/react-native-sdk +``` + +## 🧩 Quick Setup + +Before using any hooks, wrap your app in the `FlowProvider`: + +```tsx +import {FlowProvider} from "@onflow/react-native-sdk" +import flowJson from "../flow.json" + + + + +``` + +## 🪝 Available Hooks + +Here's a look at some of the hooks available. For a full list, see the [official documentation](https://developers.flow.com/tools/react-native-sdk/hooks). + +- `useFlowCurrentUser` +- `useFlowAccount` +- `useFlowBlock` +- `useFlowConfig` +- `useFlowEvents` +- `useFlowQuery` +- `useFlowRevertibleRandom` +- `useFlowMutate` +- `useFlowTransaction` +- `useFlowTransactionStatus` +- `useCrossVmTokenBalance` +- `useCrossVmBatchTransaction` + +## 🧱 Available Components + +- `` - Wallet connection button with built-in profile modal +- `` - Displays connected wallet information with disconnect option + +## 📚 Full Documentation + +Looking for full API docs, examples, and usage tips? + +👉 [Explore the official docs →](https://developers.flow.com/tools/react-sdk) diff --git a/packages/react-native-sdk/jest.config.js b/packages/react-native-sdk/jest.config.js new file mode 100644 index 000000000..c57014804 --- /dev/null +++ b/packages/react-native-sdk/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + preset: "react-native", + passWithNoTests: true, + moduleNameMapper: { + "^@walletconnect": "/src/__mocks__/noop.ts", + }, + transformIgnorePatterns: [ + "node_modules/(?!(react-native|@react-native|@onflow)/)", + ], + workerThreads: true, +} diff --git a/packages/react-native-sdk/package.json b/packages/react-native-sdk/package.json new file mode 100644 index 000000000..e4fb1850b --- /dev/null +++ b/packages/react-native-sdk/package.json @@ -0,0 +1,65 @@ +{ + "name": "@onflow/react-native-sdk", + "version": "0.1.0", + "description": "React Native library for interacting with the Flow blockchain", + "license": "Apache-2.0", + "author": "Flow Foundation", + "homepage": "https://www.flow.com", + "repository": { + "type": "git", + "url": "git+ssh://git@github.com/onflow/fcl-js.git" + }, + "bugs": { + "url": "https://github.com/onflow/fcl-js/issues" + }, + "sideEffects": false, + "main": "dist/index.js", + "module": "dist/index.module.js", + "types": "types/index.d.ts", + "source": "src/index.ts", + "files": [ + "dist", + "types", + "README.md" + ], + "scripts": { + "prepublishOnly": "npm test && npm run build", + "test": "jest", + "build": "fcl-bundle", + "build:types": "tsc", + "start": "fcl-bundle --watch" + }, + "dependencies": { + "@onflow/react-core": "0.8.1", + "@babel/runtime": "^7.25.7", + "expo-clipboard": "^7.0.0", + "@tanstack/react-query": "^5.67.3", + "react-native-svg": "^15.8.0" + }, + "peerDependencies": { + "@onflow/fcl-react-native": ">=1.20.1", + "react": "^18.0.0 || ^19.0.0", + "react-native": ">=0.70.0", + "viem": "^2.29.2" + }, + "devDependencies": { + "@babel/preset-env": "^7.26.9", + "@babel/preset-react": "^7.26.3", + "@babel/preset-typescript": "^7.25.7", + "@onflow/fcl-bundle": "1.7.1", + "@onflow/typedefs": "^1.8.0", + "@tanstack/react-query": "^5.67.3", + "@testing-library/react-native": "^12.4.3", + "@types/jest": "^29.5.13", + "@types/react": "^18.2.6", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "@typescript-eslint/parser": "^6.21.0", + "eslint": "^8.57.1", + "jest": "^29.7.0", + "react": "^18.3.1", + "react-native": "^0.76.0", + "react-test-renderer": "^18.3.1", + "typescript": "^5.9.2", + "viem": "^2.29.2" + } +} diff --git a/packages/react-native-sdk/src/__mocks__/noop.ts b/packages/react-native-sdk/src/__mocks__/noop.ts new file mode 100644 index 000000000..b1c6ea436 --- /dev/null +++ b/packages/react-native-sdk/src/__mocks__/noop.ts @@ -0,0 +1 @@ +export default {} diff --git a/packages/react-native-sdk/src/components/Connect.tsx b/packages/react-native-sdk/src/components/Connect.tsx new file mode 100644 index 000000000..83f1806d1 --- /dev/null +++ b/packages/react-native-sdk/src/components/Connect.tsx @@ -0,0 +1,226 @@ +import {useFlowCurrentUser, truncateAddress} from "@onflow/react-core" +import {UseCrossVmTokenBalanceData} from "@onflow/react-core" +import React, {useCallback, useMemo, useState} from "react" +import { + Modal, + Pressable, + StyleSheet, + Text, + TouchableOpacity, +} from "react-native" +import { + colors, + spacing, + radius, + borderWidths, + sizes, + fontSizes, + fontWeights, +} from "../styles" +import {Profile} from "./Profile" + +type BalanceType = keyof UseCrossVmTokenBalanceData + +export type TokenConfig = { + symbol: string + name: string +} & ( + | {vaultIdentifier: string; erc20Address?: never} + | {vaultIdentifier?: never; erc20Address: string} +) + +export interface ConnectProps { + /** Callback after successful connection */ + onConnect?: () => void + /** Callback after disconnection */ + onDisconnect?: () => void + /** Balance type to display in profile (cadence, evm, or combined) */ + balanceType?: BalanceType + /** Custom tokens to display balance for in profile */ + balanceTokens?: TokenConfig[] + /** Whether to show profile modal when connected (default: true) */ + modalEnabled?: boolean +} + +/** + * Connect - Wallet connection button for React Native + * + * Displays a button to connect/disconnect wallet. When connected, + * shows the truncated address and opens a profile modal on tap. + * + * @example + * ```tsx + * console.log("Connected!")} + * onDisconnect={() => console.log("Disconnected!")} + * /> + * ``` + * + * @example + * ```tsx + * // With balance display + * + * ``` + */ +export function Connect({ + onConnect, + onDisconnect, + balanceType = "cadence", + balanceTokens, + modalEnabled = true, +}: ConnectProps) { + const {user, authenticate, unauthenticate} = useFlowCurrentUser() + const [modalVisible, setModalVisible] = useState(false) + + const isLoggedIn = user?.loggedIn ?? false + + const displayAddress = useMemo(() => { + if (!user?.addr) return "" + return truncateAddress(user.addr) + }, [user?.addr]) + + const handleDisconnect = useCallback(() => { + unauthenticate() + setModalVisible(false) + onDisconnect?.() + }, [unauthenticate, onDisconnect]) + + const handlePress = useCallback(async () => { + if (isLoggedIn) { + if (modalEnabled) { + setModalVisible(true) + } else { + handleDisconnect() + } + } else { + try { + await authenticate() + onConnect?.() + } catch { + // Authentication was cancelled or failed - no action needed + } + } + }, [isLoggedIn, modalEnabled, authenticate, onConnect, handleDisconnect]) + + const buttonText = useMemo(() => { + if (isLoggedIn) return displayAddress + return "Connect Wallet" + }, [isLoggedIn, displayAddress]) + + const accessibilityLabel = useMemo(() => { + if (isLoggedIn) return `Connected: ${displayAddress}` + return "Connect wallet" + }, [isLoggedIn, displayAddress]) + + return ( + <> + + + {buttonText} + + + + {isLoggedIn && modalEnabled && ( + setModalVisible(false)} + accessible + accessibilityViewIsModal + > + setModalVisible(false)} + accessible + accessibilityRole="button" + accessibilityLabel="Close profile" + > + e.stopPropagation()} + > + + + + + )} + + ) +} + +const styles = StyleSheet.create({ + button: { + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + paddingVertical: spacing.sm, + paddingHorizontal: spacing.xl, + borderRadius: radius.sm, + minHeight: sizes.buttonMinHeight, + }, + disconnectedButton: { + backgroundColor: colors.slate900, + }, + connectedButton: { + backgroundColor: colors.transparent, + borderWidth: borderWidths.default, + borderColor: colors.slate200, + }, + buttonText: { + fontSize: fontSizes.md, + fontWeight: fontWeights.semibold, + }, + disconnectedButtonText: { + color: colors.white, + }, + connectedButtonText: { + color: colors.slate900, + }, + modalOverlay: { + flex: 1, + backgroundColor: colors.overlay, + justifyContent: "center", + alignItems: "center", + padding: spacing.lg, + }, + modalContent: { + backgroundColor: colors.white, + borderRadius: radius.lg, + width: "100%", + maxWidth: sizes.modalMaxWidth, + shadowColor: colors.slate900, + shadowOffset: {width: 0, height: 4}, + shadowOpacity: 0.15, + shadowRadius: radius.md, + elevation: 8, + }, +}) diff --git a/packages/react-native-sdk/src/components/Profile.tsx b/packages/react-native-sdk/src/components/Profile.tsx new file mode 100644 index 000000000..aec37fc61 --- /dev/null +++ b/packages/react-native-sdk/src/components/Profile.tsx @@ -0,0 +1,436 @@ +import React, {useCallback, useMemo, useState, useEffect} from "react" +import {View, Text, TouchableOpacity, StyleSheet, Linking} from "react-native" +import * as Clipboard from "expo-clipboard" +import {sansPrefix} from "@onflow/fcl-react-native" +import { + useFlowCurrentUser, + useCrossVmTokenBalance, + UseCrossVmTokenBalanceData, + useFlowChainId, + getFlowscanAccountUrl, + CONTRACT_ADDRESSES, + truncateAddress, +} from "@onflow/react-core" +import type {TokenConfig} from "./Connect" +import { + UserIcon, + CopyIcon, + CheckIcon, + LogOutIcon, + ExternalLinkIcon, +} from "../icons" +import { + colors, + spacing, + radius, + borderWidths, + sizes, + fontSizes, + fontWeights, +} from "../styles" + +type BalanceType = keyof UseCrossVmTokenBalanceData + +export interface ProfileProps { + /** Callback when user disconnects */ + onDisconnect?: () => void + /** Balance type to display (cadence, evm, or combined) */ + balanceType?: BalanceType + /** Custom tokens to display balance for */ + balanceTokens?: TokenConfig[] +} + +/** + * Profile - Displays user wallet information with balance + * + * Shows the connected wallet address and token balance. + * Provides disconnect functionality and links to Flowscan. + * + * @example + * ```tsx + * console.log("Disconnected")} + * balanceType="cadence" + * /> + * ``` + */ +export const Profile: React.FC = ({ + onDisconnect, + balanceType = "cadence", + balanceTokens, +}) => { + const {user, unauthenticate} = useFlowCurrentUser() + const {data: chainId} = useFlowChainId() + const [copied, setCopied] = useState(false) + + // Default token configuration for FlowToken + const defaultTokens: TokenConfig[] = useMemo(() => { + if (!chainId) return [] + + const getFlowTokenAddress = () => { + if (chainId === "emulator" || chainId === "local") + return CONTRACT_ADDRESSES.local.FlowToken + return chainId === "testnet" + ? CONTRACT_ADDRESSES.testnet.FlowToken + : CONTRACT_ADDRESSES.mainnet.FlowToken + } + + const address = sansPrefix(getFlowTokenAddress()) + return [ + { + symbol: "FLOW", + name: "Flow Token", + vaultIdentifier: `A.${address}.FlowToken.Vault`, + }, + ] + }, [chainId]) + + // Use provided tokens or default to FLOW + const availableTokens = useMemo( + () => + balanceTokens && balanceTokens.length > 0 ? balanceTokens : defaultTokens, + [balanceTokens, defaultTokens] + ) + + const [selectedToken, setSelectedToken] = useState( + availableTokens[0] + ) + + // Update selectedToken when availableTokens changes + useEffect(() => { + if (!availableTokens || availableTokens.length === 0) { + setSelectedToken(undefined) + return + } + + setSelectedToken(prev => { + if (!prev) return availableTokens[0] + + const updatedToken = availableTokens.find(t => t.symbol === prev.symbol) + if (!updatedToken) return availableTokens[0] + + if ( + (!prev.vaultIdentifier && updatedToken.vaultIdentifier) || + (!prev.erc20Address && updatedToken.erc20Address) + ) { + return updatedToken + } + + return prev + }) + }, [availableTokens]) + + const {data: balanceData} = useCrossVmTokenBalance({ + owner: user?.addr, + vaultIdentifier: selectedToken?.vaultIdentifier, + erc20Address: selectedToken?.erc20Address, + query: { + enabled: + !!user?.addr && + !!chainId && + !!selectedToken && + (!!selectedToken?.vaultIdentifier || !!selectedToken?.erc20Address), + }, + }) + + const displayAddress = useMemo(() => { + if (!user?.addr) return "" + return truncateAddress(user.addr) + }, [user?.addr]) + + const flowscanUrl = useMemo( + () => getFlowscanAccountUrl(user?.addr || "", chainId), + [user?.addr, chainId] + ) + + const displayBalance = useMemo(() => { + if ( + !balanceData || + typeof balanceData === "string" || + !balanceData[balanceType]?.formatted + ) { + return "0" + } + return Number(balanceData[balanceType].formatted).toLocaleString( + undefined, + { + maximumFractionDigits: 4, + minimumFractionDigits: 0, + } + ) + }, [balanceData, balanceType]) + + const handleCopy = useCallback(async () => { + if (user?.addr) { + try { + await Clipboard.setStringAsync(user.addr) + setCopied(true) + setTimeout(() => setCopied(false), 1500) + } catch { + // Silently fail - clipboard may not be available in all environments + } + } + }, [user?.addr]) + + const handleOpenFlowscan = useCallback(async () => { + if (flowscanUrl) { + try { + await Linking.openURL(flowscanUrl) + } catch { + // Silently fail - URL may not be supported + } + } + }, [flowscanUrl]) + + const handleDisconnect = useCallback(() => { + unauthenticate() + onDisconnect?.() + }, [unauthenticate, onDisconnect]) + + const handleSelectToken = useCallback((token: TokenConfig) => { + setSelectedToken(token) + }, []) + + // Not connected state + if (!user?.loggedIn) { + return ( + + + + + No connected wallet + + ) + } + + // Connected state + return ( + + + + + + + {displayAddress} + {flowscanUrl && ( + + + + )} + + + + {availableTokens.length > 1 && ( + + Token + + {availableTokens.map(token => ( + handleSelectToken(token)} + accessible + accessibilityRole="radio" + accessibilityState={{ + selected: selectedToken?.symbol === token.symbol, + }} + > + + {token.symbol} + + + ))} + + + )} + + + Balance + + {displayBalance} + + {selectedToken?.symbol || "FLOW"} + + + + + + + {copied ? ( + + ) : ( + + )} + + {copied ? "Copied!" : "Copy Address"} + + + + + + Disconnect + + + + ) +} + +const styles = StyleSheet.create({ + container: { + padding: spacing.lg, + }, + centerContent: { + alignItems: "center", + justifyContent: "center", + paddingVertical: spacing.xxl, + }, + + avatarPlaceholder: { + width: sizes.avatar, + height: sizes.avatar, + borderRadius: radius.full, + backgroundColor: colors.slate100, + justifyContent: "center", + alignItems: "center", + marginBottom: spacing.sm, + }, + notConnectedText: { + fontSize: fontSizes.sm, + fontWeight: fontWeights.medium, + color: colors.slate500, + }, + + header: { + alignItems: "center", + marginBottom: spacing.lg, + }, + avatar: { + width: sizes.avatar, + height: sizes.avatar, + borderRadius: radius.full, + backgroundColor: colors.slate100, + justifyContent: "center", + alignItems: "center", + marginBottom: spacing.sm, + }, + addressRow: { + flexDirection: "row", + alignItems: "center", + gap: spacing.xs, + }, + address: { + fontSize: fontSizes.md, + fontWeight: fontWeights.semibold, + color: colors.slate900, + }, + + tokenSelector: { + marginBottom: spacing.md, + }, + sectionLabel: { + fontSize: fontSizes.xs, + fontWeight: fontWeights.semibold, + color: colors.slate500, + marginBottom: spacing.xs, + }, + tokenList: { + flexDirection: "row", + flexWrap: "wrap", + gap: spacing.xs, + }, + tokenOption: { + paddingHorizontal: spacing.md, + paddingVertical: spacing.xs, + borderRadius: radius.sm, + borderWidth: borderWidths.default, + borderColor: colors.slate200, + backgroundColor: colors.white, + }, + tokenOptionSelected: { + borderColor: colors.primary, + backgroundColor: colors.primaryLight, + }, + tokenSymbol: { + fontSize: fontSizes.sm, + fontWeight: fontWeights.semibold, + color: colors.slate500, + }, + tokenSymbolSelected: { + color: colors.primary, + }, + + balanceCard: { + backgroundColor: colors.slate50, + borderRadius: radius.md, + borderWidth: borderWidths.default, + borderColor: colors.slate200, + padding: spacing.md, + marginBottom: spacing.md, + }, + balanceRow: { + flexDirection: "row", + alignItems: "baseline", + }, + balanceAmount: { + fontSize: fontSizes.lg, + fontWeight: fontWeights.bold, + color: colors.slate900, + }, + balanceSymbol: { + fontSize: fontSizes.sm, + fontWeight: fontWeights.medium, + color: colors.slate500, + marginLeft: spacing.xs, + }, + + actions: { + flexDirection: "row", + gap: spacing.sm, + }, + actionButton: { + flex: 1, + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + paddingVertical: spacing.sm, + paddingHorizontal: spacing.md, + borderRadius: radius.sm, + borderWidth: borderWidths.default, + borderColor: colors.slate200, + backgroundColor: colors.white, + gap: spacing.xs, + }, + actionText: { + fontSize: fontSizes.sm, + fontWeight: fontWeights.medium, + color: colors.slate900, + }, +}) diff --git a/packages/react-native-sdk/src/components/index.ts b/packages/react-native-sdk/src/components/index.ts new file mode 100644 index 000000000..922f30930 --- /dev/null +++ b/packages/react-native-sdk/src/components/index.ts @@ -0,0 +1,4 @@ +export {Connect} from "./Connect" +export type {ConnectProps, TokenConfig} from "./Connect" +export {Profile} from "./Profile" +export type {ProfileProps} from "./Profile" diff --git a/packages/react-native-sdk/src/icons/CheckIcon.tsx b/packages/react-native-sdk/src/icons/CheckIcon.tsx new file mode 100644 index 000000000..adb0648de --- /dev/null +++ b/packages/react-native-sdk/src/icons/CheckIcon.tsx @@ -0,0 +1,25 @@ +import React from "react" +import {Svg, Path} from "react-native-svg" + +interface IconProps { + size?: number + color?: string +} + +export const CheckIcon: React.FC = ({ + size = 24, + color = "#0F172A", +}) => ( + + + +) diff --git a/packages/react-native-sdk/src/icons/CopyIcon.tsx b/packages/react-native-sdk/src/icons/CopyIcon.tsx new file mode 100644 index 000000000..c1be5eeeb --- /dev/null +++ b/packages/react-native-sdk/src/icons/CopyIcon.tsx @@ -0,0 +1,26 @@ +import React from "react" +import {Svg, Path, Rect} from "react-native-svg" + +interface IconProps { + size?: number + color?: string +} + +export const CopyIcon: React.FC = ({ + size = 24, + color = "#0F172A", +}) => ( + + + + +) diff --git a/packages/react-native-sdk/src/icons/ExternalLinkIcon.tsx b/packages/react-native-sdk/src/icons/ExternalLinkIcon.tsx new file mode 100644 index 000000000..0832de76a --- /dev/null +++ b/packages/react-native-sdk/src/icons/ExternalLinkIcon.tsx @@ -0,0 +1,27 @@ +import React from "react" +import {Svg, Path} from "react-native-svg" + +interface IconProps { + size?: number + color?: string +} + +export const ExternalLinkIcon: React.FC = ({ + size = 16, + color = "#64748B", +}) => ( + + + + + +) diff --git a/packages/react-native-sdk/src/icons/LogOutIcon.tsx b/packages/react-native-sdk/src/icons/LogOutIcon.tsx new file mode 100644 index 000000000..503bb94ab --- /dev/null +++ b/packages/react-native-sdk/src/icons/LogOutIcon.tsx @@ -0,0 +1,27 @@ +import React from "react" +import {Svg, Path} from "react-native-svg" + +interface IconProps { + size?: number + color?: string +} + +export const LogOutIcon: React.FC = ({ + size = 24, + color = "#0F172A", +}) => ( + + + + + +) diff --git a/packages/react-native-sdk/src/icons/UserIcon.tsx b/packages/react-native-sdk/src/icons/UserIcon.tsx new file mode 100644 index 000000000..1f9ee5e44 --- /dev/null +++ b/packages/react-native-sdk/src/icons/UserIcon.tsx @@ -0,0 +1,26 @@ +import React from "react" +import {Svg, Path, Circle} from "react-native-svg" + +interface IconProps { + size?: number + color?: string +} + +export const UserIcon: React.FC = ({ + size = 24, + color = "#64748B", +}) => ( + + + + +) diff --git a/packages/react-native-sdk/src/icons/index.ts b/packages/react-native-sdk/src/icons/index.ts new file mode 100644 index 000000000..6249653a2 --- /dev/null +++ b/packages/react-native-sdk/src/icons/index.ts @@ -0,0 +1,5 @@ +export {UserIcon} from "./UserIcon" +export {CopyIcon} from "./CopyIcon" +export {CheckIcon} from "./CheckIcon" +export {LogOutIcon} from "./LogOutIcon" +export {ExternalLinkIcon} from "./ExternalLinkIcon" diff --git a/packages/react-native-sdk/src/index.ts b/packages/react-native-sdk/src/index.ts new file mode 100644 index 000000000..a6c2e583c --- /dev/null +++ b/packages/react-native-sdk/src/index.ts @@ -0,0 +1,51 @@ +// Re-export types from react-core +export type {FlowNetwork, FlowConfig} from "@onflow/react-core" + +// Re-export hooks from react-core +export { + useFlowCurrentUser, + useFlowAuthz, + useFlowAccount, + useFlowBlock, + useFlowChainId, + useFlowClient, + useFlowConfig, + useFlowEvents, + useFlowMutate, + useFlowQuery, + useFlowQueryRaw, + useFlowRevertibleRandom, + useCrossVmBatchTransaction, + useCrossVmTokenBalance, + useFlowTransaction, + useFlowTransactionStatus, + useCrossVmSpendNft, + useCrossVmSpendToken, + useCrossVmBridgeNftFromEvm, + useCrossVmBridgeNftToEvm, + useCrossVmBridgeTokenFromEvm, + useCrossVmBridgeTokenToEvm, + useCrossVmTransactionStatus, + useFlowNftMetadata, + useFlowScheduledTransactionList, + useFlowScheduledTransaction, + useFlowScheduledTransactionSetup, + useFlowScheduledTransactionCancel, + ScheduledTransactionPriority, + ScheduledTransactionStatus, +} from "@onflow/react-core" + +// Re-export utilities from react-core +export { + CONTRACT_ADDRESSES, + getFlowscanAccountUrl, + getFlowscanTxUrl, + getFlowscanScheduledTxUrl, +} from "@onflow/react-core" + +// Re-export types from hooks +export type {NftViewResult, ScheduledTransaction} from "@onflow/react-core" + +// React Native specific components and providers +export * from "./components" +export * from "./provider" diff --git a/packages/react-native-sdk/src/provider/FlowProvider.tsx b/packages/react-native-sdk/src/provider/FlowProvider.tsx new file mode 100644 index 000000000..8d02776c9 --- /dev/null +++ b/packages/react-native-sdk/src/provider/FlowProvider.tsx @@ -0,0 +1,89 @@ +import React, {useState, PropsWithChildren, useMemo, useEffect} from "react" +import { + FlowConfig, + FlowConfigContext, + FlowClientContext, + FlowQueryClientProvider, + GlobalTransactionProvider, +} from "@onflow/react-core" +import {DefaultOptions, QueryClient} from "@tanstack/react-query" +import { + createFlowClient, + ConnectModalProvider, + config, +} from "@onflow/fcl-react-native" + +export interface FlowProviderProps { + config?: FlowConfig + queryClient?: QueryClient + flowClient?: ReturnType + flowJson?: Record +} + +const defaultQueryOptions: DefaultOptions = { + queries: { + retry: false, + staleTime: 0, + refetchOnWindowFocus: false, + refetchOnReconnect: false, + refetchIntervalInBackground: false, + }, +} + +export function FlowProvider({ + config: initialConfig = {}, + queryClient: _queryClient, + flowClient: _flowClient, + flowJson, + children, +}: PropsWithChildren) { + const [queryClient] = useState( + () => _queryClient ?? new QueryClient({defaultOptions: defaultQueryOptions}) + ) + + const flowClient = useMemo(() => { + if (_flowClient) return _flowClient + return createFlowClient({ + accessNodeUrl: initialConfig.accessNodeUrl!, + discoveryWallet: initialConfig.discoveryWallet, + discoveryWalletMethod: initialConfig.discoveryWalletMethod, + discoveryAuthnEndpoint: initialConfig.discoveryAuthnEndpoint, + discoveryAuthnInclude: initialConfig.discoveryAuthnInclude, + discoveryAuthnExclude: initialConfig.discoveryAuthnExclude, + flowJson, + flowNetwork: initialConfig.flowNetwork, + computeLimit: initialConfig.computeLimit, + walletconnectProjectId: initialConfig.walletconnectProjectId, + walletconnectDisableNotifications: + initialConfig.walletconnectDisableNotifications, + appDetailTitle: initialConfig.appDetailTitle, + appDetailIcon: initialConfig.appDetailIcon, + appDetailDescription: initialConfig.appDetailDescription, + appDetailUrl: initialConfig.appDetailUrl, + serviceOpenIdScopes: initialConfig.serviceOpenIdScopes, + }) + }, [_flowClient, initialConfig, flowJson]) + + // Set discovery.authn.endpoint in global FCL config for ServiceDiscovery + // This is needed for the ConnectModal to work correctly and retrieve the endpoint to load wallets + useEffect(() => { + if (initialConfig.discoveryAuthnEndpoint) { + config().put( + "discovery.authn.endpoint", + initialConfig.discoveryAuthnEndpoint + ) + } + }, [initialConfig.discoveryAuthnEndpoint]) + + return ( + + + + + {children} + + + + + ) +} diff --git a/packages/react-native-sdk/src/provider/index.ts b/packages/react-native-sdk/src/provider/index.ts new file mode 100644 index 000000000..9f2c6ea02 --- /dev/null +++ b/packages/react-native-sdk/src/provider/index.ts @@ -0,0 +1,3 @@ +export {FlowProvider} from "./FlowProvider" +export type {FlowProviderProps} from "./FlowProvider" +export {useFlowQueryClient} from "@onflow/react-core" diff --git a/packages/react-native-sdk/src/styles/colors.ts b/packages/react-native-sdk/src/styles/colors.ts new file mode 100644 index 000000000..ac2b5f7ab --- /dev/null +++ b/packages/react-native-sdk/src/styles/colors.ts @@ -0,0 +1,20 @@ +export const colors = { + // Slate palette + slate900: "#0F172A", // Primary dark (text, buttons) + slate500: "#64748B", // Secondary text, icons + slate200: "#E2E8F0", // Borders + slate100: "#F1F5F9", // Avatar backgrounds + slate50: "#F8FAFC", // Card backgrounds + + // Core + white: "#FFFFFF", + transparent: "transparent", + + // Semantic + success: "#16A34A", // Green for success/check + primary: "#2563EB", // Blue for selected state + primaryLight: "#EFF6FF", // Blue-50 for selected bg + + // Overlay + overlay: "rgba(0, 0, 0, 0.5)", +} diff --git a/packages/react-native-sdk/src/styles/dimensions.ts b/packages/react-native-sdk/src/styles/dimensions.ts new file mode 100644 index 000000000..ccbb02108 --- /dev/null +++ b/packages/react-native-sdk/src/styles/dimensions.ts @@ -0,0 +1,40 @@ +export const spacing = { + xs: 8, // gaps, small margins + sm: 12, // button padding, margins + md: 16, // card padding, margins + lg: 20, // container padding + xl: 24, // button horizontal padding + xxl: 48, // large vertical padding +} + +export const radius = { + sm: 8, // buttons, tokens, action buttons + md: 12, // cards + lg: 16, // modals + full: 32, // avatars (half of avatar size) +} + +export const borderWidths = { + default: 1, +} + +export const sizes = { + avatar: 64, + iconSm: 16, + iconMd: 32, + buttonMinHeight: 48, + modalMaxWidth: 400, +} + +export const fontSizes = { + xs: 12, // labels + sm: 14, // body text, symbols + md: 16, // addresses, button text + lg: 28, // balance amount +} + +export const fontWeights = { + medium: "500" as const, + semibold: "600" as const, + bold: "700" as const, +} diff --git a/packages/react-native-sdk/src/styles/index.ts b/packages/react-native-sdk/src/styles/index.ts new file mode 100644 index 000000000..a9d0a9e8f --- /dev/null +++ b/packages/react-native-sdk/src/styles/index.ts @@ -0,0 +1,9 @@ +export {colors} from "./colors" +export { + spacing, + radius, + borderWidths, + sizes, + fontSizes, + fontWeights, +} from "./dimensions" diff --git a/packages/react-native-sdk/tsconfig.json b/packages/react-native-sdk/tsconfig.json new file mode 100644 index 000000000..bc84097d0 --- /dev/null +++ b/packages/react-native-sdk/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig", + "include": ["src/**/*.ts", "src/**/*.tsx"], + "compilerOptions": { + "declarationDir": "types", + "rootDir": "src", + "jsx": "react", + "lib": ["ES2015", "ES2022.Error"], + "skipLibCheck": true, + "paths": { + "react": ["../../node_modules/@types/react/index"] + } + } +} diff --git a/packages/react-sdk/src/components/Connect.tsx b/packages/react-sdk/src/components/Connect.tsx index b4aa03bea..f68b05cd7 100644 --- a/packages/react-sdk/src/components/Connect.tsx +++ b/packages/react-sdk/src/components/Connect.tsx @@ -1,5 +1,5 @@ import React, {useState} from "react" -import {useFlowCurrentUser} from "@onflow/react-core" +import {useFlowCurrentUser, truncateAddress} from "@onflow/react-core" import {UseCrossVmTokenBalanceData} from "@onflow/react-core" import {Button, ButtonProps} from "./internal/Button" import {Dialog} from "./internal/Dialog" @@ -52,9 +52,7 @@ export const Connect: React.FC = ({ : "flow-max-w-md" const displayAddress = - user?.loggedIn && user.addr - ? `${user.addr.slice(0, 6)}...${user.addr.slice(-4)}` - : "" + user?.loggedIn && user.addr ? truncateAddress(user.addr) : "" const handleButtonClick = async () => { if (user?.loggedIn) { diff --git a/packages/react-sdk/src/components/Profile.tsx b/packages/react-sdk/src/components/Profile.tsx index 5a9b4fd3b..25f988a70 100644 --- a/packages/react-sdk/src/components/Profile.tsx +++ b/packages/react-sdk/src/components/Profile.tsx @@ -10,7 +10,8 @@ import { TabPanel, TabPanels, } from "@headlessui/react" -import {useFlowCurrentUser} from "@onflow/react-core" +import {sansPrefix} from "@onflow/fcl" +import {useFlowCurrentUser, truncateAddress} from "@onflow/react-core" import { useCrossVmTokenBalance, UseCrossVmTokenBalanceData, @@ -64,7 +65,7 @@ export const Profile: React.FC = ({ : CONTRACT_ADDRESSES.mainnet.FlowToken } - const address = getFlowTokenAddress().replace("0x", "") + const address = sansPrefix(getFlowTokenAddress()) return [ { symbol: "FLOW", @@ -132,9 +133,7 @@ export const Profile: React.FC = ({ }) const displayAddress = - user?.loggedIn && user.addr - ? `${user.addr.slice(0, 6)}...${user.addr.slice(-4)}` - : "" + user?.loggedIn && user.addr ? truncateAddress(user.addr) : "" const flowscanUrl = getFlowscanAccountUrl(user?.addr || "", chainId) diff --git a/packages/react-sdk/src/components/ScheduledTransactionList.tsx b/packages/react-sdk/src/components/ScheduledTransactionList.tsx index 4bc275dad..1c5534a7c 100644 --- a/packages/react-sdk/src/components/ScheduledTransactionList.tsx +++ b/packages/react-sdk/src/components/ScheduledTransactionList.tsx @@ -14,7 +14,7 @@ import {TrashIcon} from "../icons/TrashIcon" import {FlowIcon} from "../icons/FlowIcon" import {ExternalLinkIcon} from "../icons/ExternalLink" import {twMerge} from "tailwind-merge" -import {useFlowQueryClient} from "../provider/FlowQueryClient" +import {useFlowQueryClient} from "@onflow/react-core" import {useFlowChainId} from "@onflow/react-core" import {getFlowscanScheduledTxUrl} from "@onflow/react-core" diff --git a/packages/react-sdk/src/components/TransactionButton.tsx b/packages/react-sdk/src/components/TransactionButton.tsx index c042fe58f..a3d798842 100644 --- a/packages/react-sdk/src/components/TransactionButton.tsx +++ b/packages/react-sdk/src/components/TransactionButton.tsx @@ -4,7 +4,7 @@ import {Button, ButtonProps} from "./internal/Button" import {StyleWrapper} from "./internal/StyleWrapper" import {UseMutationOptions} from "@tanstack/react-query" import {type mutate} from "@onflow/fcl" -import {useGlobalTransaction} from "../provider/GlobalTransactionProvider" +import {useGlobalTransaction} from "@onflow/react-core" interface TransactionButtonProps extends Omit { diff --git a/packages/react-sdk/src/provider/FlowProvider.tsx b/packages/react-sdk/src/provider/FlowProvider.tsx index 997203092..d9ea775bb 100644 --- a/packages/react-sdk/src/provider/FlowProvider.tsx +++ b/packages/react-sdk/src/provider/FlowProvider.tsx @@ -3,12 +3,12 @@ import { FlowConfig, FlowConfigContext, FlowClientContext, + FlowQueryClientProvider, + GlobalTransactionProvider, } from "@onflow/react-core" import {DefaultOptions, QueryClient} from "@tanstack/react-query" -import {FlowQueryClientProvider} from "./FlowQueryClient" import {createFlowClient} from "@onflow/fcl" import {ThemeProvider, Theme} from "../core/theme" -import {GlobalTransactionProvider} from "./GlobalTransactionProvider" import tailwindStyles from "../styles/tailwind.css" import {DarkModeProvider} from "./DarkModeProvider" diff --git a/packages/react-sdk/src/provider/FlowQueryClient.tsx b/packages/react-sdk/src/provider/FlowQueryClient.tsx deleted file mode 100644 index 42f8974cb..000000000 --- a/packages/react-sdk/src/provider/FlowQueryClient.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import React, {PropsWithChildren} from "react" -import {QueryClient} from "@tanstack/react-query" -import {FlowQueryClientContext} from "@onflow/react-core" - -export function FlowQueryClientProvider({ - queryClient, - children, -}: PropsWithChildren<{queryClient: QueryClient}>) { - return ( - - ) -} - -// Re-export the hook from react-core for convenience -export {useFlowQueryClient} from "@onflow/react-core" diff --git a/packages/react-sdk/src/provider/index.ts b/packages/react-sdk/src/provider/index.ts index 00727d831..6c5f33c8d 100644 --- a/packages/react-sdk/src/provider/index.ts +++ b/packages/react-sdk/src/provider/index.ts @@ -1,3 +1,3 @@ export {FlowProvider} from "./FlowProvider" -export {FlowQueryClientProvider, useFlowQueryClient} from "./FlowQueryClient" +export {useFlowQueryClient} from "@onflow/react-core" export {DarkModeProvider, useDarkMode} from "./DarkModeProvider"